Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[API] Single Select Component #140

Closed
segunadebayo opened this issue Oct 3, 2019 · 32 comments
Closed

[API] Single Select Component #140

segunadebayo opened this issue Oct 3, 2019 · 32 comments
Labels
Type: API discussion 💡 It's just a idea worth looking into, but doesn't mean it's priority.

Comments

@segunadebayo
Copy link
Member

Following our discussion in Issue #38. I thought to put down my thoughts about
the Single Select component and the API I have in mind.

NB: I know there are other use cases, like Multiple Selects and ComboBox, but
we're keeping it simple for now. We'll start with a Single Select Component

The Goal:

Create a select component that works just like the native select and accessible,
composable and super easy to style.

The single select will follow WAI-ARIA specs for the list box pattern. These are the
key resources we need to create this Select

Key Features:

  • Typeahead support: When the select is open and focus is on the select list box
    • Typing the first letter of an option sends focus to that option.
    • Type multiple characters in rapid succession: focus moves to the next item
      with a name that starts with the string of characters typed.
  • Keyboard navigation:
    • Using the up and down arrow should navigate the options. Any option that's
      disabled should be skipped in the navigation.
    • The Home and End key should select the first and last option respectively.
  • Scrolling into view: In the event, the options are quite many and we navigate
    via keyboard or typeahead, any option is focused that isn't (fully) visible
    should be scrolled into view. Perhaps scroll-into-view-if-needed might help.
  • Auto select:
    • If autoSelect is true, highlighting an option must also select that option
    • If autoSelect is false, a highlighted option must be manually selected
      using the SPACEBAR or ENTER key.
  • Virtualize Menu: If there's a large number of options, we might need to
    improve render performance by using react-virtualized

Import

Component Parts:

  • Select: The wrapper that provides the context and functionalities
  • SelectControl: The element that triggers the list box. By default, it renders a
    button but can also use a render prop in case user needs full control of the rendering.
  • SelectMenu: The wrapper for the popover. It composes the Popper component.
    It can also use a render prop incase user needs access to the interal state.
  • SelectMenuList: The listbox that wraps the options. It provides the keyboard
    navigation and typeahead functions.
  • SelectIndicator: The wrapper for the dropdown icon.
  • SelectOption: Each option in the select.
  • SelectOptionGroup: A wrapper for a set of options that can be labeled. Similar
    to the <optgroup> in the native browser select.

Usage

<Select>
  <SelectControl>
    <SelectLabel>Option 1</SelectLabel>
    <SelectIndicator>
      <Icon name="down-up-arrow" />
    </SelectIndicator>
  </SelectControl>
  <SelectMenu>
    <SelectMenuList>
      <SelectOption value="opt1">SelectOption 1</SelectOption>
      <SelectOption value="opt2">SelectOption 2</SelectOption>
      <SelectOption value="opt3">SelectOption 3</SelectOption>
    </SelectMenuList>
  </SelectMenu>
</Select>

The Select should also be able to render an option group. If passed
isDisabled, the options should also be disabled.

<Select defaultIsOpen={true} defaultValue="css">
  <SelectControl>Select Option</SelectControl>
  <SelectMenu>
    <SelectMenuList>
      <SelectOption value="html">HTML</SelectOption>
      <SelectOption value="css">CSS</SelectOption>
      <SelectOptionGroup label="Frameworks" isDisabled>
        <SelectOption value="react">React</SelectOption>
        <SelectOption value="vue">Vue</SelectOption>
        <SelectOption value="angular">Angular</SelectOption>
      </SelectOptionGroup>
    </SelectMenuList>
  </SelectMenu>
</Select>

Props

Select Props (Provides Context)

  • defaultIsOpen: If true, the select should be open initially.
  • isOpen: If true, the select should be open in controlled mode.
  • defaultHighlightedIndex: the index of the item that should be highlighted
    initially.
  • autoSelect: If true, the option will be selected as you navigate through
    them.
  • closeOnBlur: If true, the select menu will close on blur or outside click
  • closeOnEsc: If true, the select menu will close when you press escape
  • closeOnSelect: If true, the select menu will close when you select an
    option.
  • defaultValue: The initial selected value
  • value: The selected value
  • onChange: Callback fired when an option is selected
  • isDisabled: If true the select control will be disabled
  • isInvalid: If true, the select control will have aria-invalid set to true
  • isReadOnly: If true, the select will be in read-only mode
  • children: the content of the select. It can also take a render prop that
    provides:
    • selectedItem
    • highlightedIndex
    • isOpen
    • onClose

SelectOptionGroup Props (composes Box)

  • isDisabled: If true, all the SelectOption that it wraps will be disabled
  • label: The label for the option group

SelectOption Props (composes PseudoBox)

  • isSelected
  • isHighlighted
  • value
  • children
@segunadebayo segunadebayo added the Type: API discussion 💡 It's just a idea worth looking into, but doesn't mean it's priority. label Oct 3, 2019
@aaronmcadam
Copy link
Contributor

aaronmcadam commented Oct 3, 2019

My biggest concern with the Select component is whether it will be easy to test in unit tests with Jest and End to End tests with Cypress. react-select, as least in version 2, makes it very hard to choose items.

Here's an example:

/**
 * Create a Project
 */
cy.getByTestId("button-add-project").click();
cy.getByTestId("input-project-title").type("E2E Test Project");
cy.getByTestId("button-wizard-next").click();
cy.getByTestId("input-project-description").type(
  "E2E Test Project description"
);
cy.getByTestId("button-wizard-next").click();
cy.getByTestId("select-agency").click();
// Choose 'Testing Agency'
cy.get("#react-select-2-option-4").click();

/**
 * Clicking multiple times makes this test more resilient
 * @see https://github.com/cypress-io/cypress/issues/1486#issuecomment-450151465
 * @see https://github.com/cypress-io/cypress/pull/2982
 */
cy.getByTestId("select-client")
  .click()
  .click()
  .click();
// Choose 'Testing Client'
cy.get("#react-select-3-option-0").click();

cy.getByTestId("button-wizard-next").click();
cy.getByTestId("select-template")
  .eq(0)
  .click();
cy.getByTestId("button-wizard-complete").click();

I'm hoping your approach of putting accessibility first (which is really great!) will mean this won't be a concern!

@aaronmcadam
Copy link
Contributor

aaronmcadam commented Nov 28, 2019

Did we get anywhere with this component @segunadebayo? Did you find any third party components that might fit in with Chakra? I need to implement a single select in my current project so I'm just about to start researching. If I find anything good, I could post it here if that would help?

@segunadebayo
Copy link
Member Author

Hi @aaronmcadam,

I've built a custom select already, it's in the dev-ts branch, but it needs some cleanup and type definition. It'll be in the next release.

However, if you find an implementation other than react-select or downshift please let me know.

@aaronmcadam
Copy link
Contributor

Hi @segunadebayo, thanks for getting back to me. I ended up using an old component we had that uses react-select. It is an older 1.x version with the testing problems mentioned above. I don't know if react-select v2 produces more semantic markup or is less flaky in tests.

That's great news that you've got something working in the TypeScript branch. I'd like to give you a hand with some of the work when I get a chance.

@aaronmcadam
Copy link
Contributor

I did have a look at Reach UI's Combobox, and while it's a great example of how to build an accessible and testable component, it didn't fit my simple needs and the needs of this RFC.

@segunadebayo
Copy link
Member Author

I'm curious @aaronmcadam. What do you mean by "simple needs"? Just to be sure what I've worked on covers this 😄

@aaronmcadam
Copy link
Contributor

I'm curious @aaronmcadam. What do you mean by "simple needs"? Just to be sure what I've worked on covers this

The same needs as mentioned above: just a select component that allows you choose from a list of options. The combobox is more of an extended text input, in that you can choose an option or type your own value. Does that make sense?

@aaronmcadam
Copy link
Contributor

@segunadebayo I do need to be able to have a more complex option than just text though. In my case I need to have an icon beside some text. I'm AFK at the moment but I'll attach a screenshot tomorrow

@segunadebayo
Copy link
Member Author

@aaronmcadam. I've got you covered then.

@aaronmcadam
Copy link
Contributor

@segunadebayo For clarity, here's my use case:

CleanShot 2019-11-29 at 12 17 08

@segunadebayo
Copy link
Member Author

@aaronmcadam There won't be an input to search options in the SimpleSelect I've worked on. What I have mimics native HTML select and supports typeahead/rapid typeahead.

@Martinnord
Copy link
Contributor

Hello!

Are there any updates on this? It would be really cool to have this in this awesome lib!

Cheers!

@segunadebayo
Copy link
Member Author

Hi @Martinnord, The select component is in progress, you can track it in the dev-ts branch. I believe the first version will be out in our next release.

@Martinnord
Copy link
Contributor

@segunadebayo Cool! Will keep an eye on that branch!

@Enigma10
Copy link

Enigma10 commented Mar 3, 2020

@segunadebayo I want to help you this component. Can you guide me?. I am beginner in open source.

@segunadebayo
Copy link
Member Author

@Enigma10, Thanks for offering to help. For now, we've de-scoped the Select component to help us focus on the next major release.

Once we get back to it, I'll drop a comment here so I can guide you.

Cheers.

@adrianoresende
Copy link
Contributor

adrianoresende commented Aug 11, 2020

Hello there,

@segunadebayo We decided to use your Chakra as the initial DS, congratulations on your project, it's great. 👏

So, we missed the searchable select and I read the issue here and we want to know if it has ETA to launch?

We can access the component to see if we can help?

@tomdohnal
Copy link
Contributor

@segunadebayo
Hi, now that the v1 is released (congrats!), is this component something you would consider adding to the library?
I'd be happy to help you out with that if that's something you'd consider.

@TaylorFacen
Copy link

Hi! I'm checking in to see if there's a plan to implement a searchable select? styling with react-select is 👎🏾

@csandman
Copy link

csandman commented Apr 5, 2021

@TaylorFacen You should check out my wrapper for react-select. I spent a decent amount of time replacing the react-select styles with the chakra ones, in some cases just replacing the components entirely.

EDIT

I've noticed that this has gotten a positive reception so I figured I'd post an update. The wrapper I posted is now updated to more accurately work with the react-select controls, and also now has a size prop! it can accept sm, md, and lg and it reflects the sizes of the normal chakra text input. I also included a wrapper for the async version.

EDIT 2

I made it into an NPM package! https://www.npmjs.com/package/chakra-react-select

@onurbamaro
Copy link

@TaylorFacen You should check out my wrapper for react-select. I spent a decent amount of time replacing the react-select styles with the chakra ones, in some cases just replacing the components entirely.

Nice job! I'm kinda new to software development and a documentation on this would be nice. Do you have any? If not, could help me with something?

Thanks in advance

@csandman
Copy link

@onurbamaro I don't have any documentation but it should take the same props as the original package. As long as you have react-select and chakra installed, just copy the multi-select component into your app somewhere and import it instead of react-select. The rest of the docs can be found at the react-select website: https://react-select.com/home.

If you have a specific question, feel free to ask!

@onurbamaro
Copy link

@onurbamaro I don't have any documentation but it should take the same props as the original package. As long as you have react-select and chakra installed, just copy the multi-select component into your app somewhere and import it instead of react-select. The rest of the docs can be found at the react-select website: https://react-select.com/home.

If you have a specific question, feel free to ask!

Oh, now I get it. That's what I was looking for! Thank you and nice job once again, this is going to help a lot!

@csandman
Copy link

@onurbamaro You're welcome!

@tannerbaum
Copy link

@segunadebayo Has there been any consideration into expanding the select component to include search of extending it in a new component?

@csandman did great work on his own solution, but having something directly from Chakra without relying on React-Select that is also in the Chakra TS ecosystem would be nice.

@csandman
Copy link

@tannerbaum I definitely agree that it would be great to have a combobox type component native to the Chakra lib, the component I made was only ever supposed to be a holdover until something like that exists

@aaronmcadam
Copy link
Contributor

@tannerbaum There's been some experiments using Downshift on Chakra UI Pro. I've not had a chance to play with the component yet, though. But if the component is stable enough, it may make its way into the library.

@alexkreidler
Copy link
Contributor

There's also a project that's focused on autocomplete features that uses the Downshift library's ComboBox:

https://github.com/koolamusic/chakra-ui-autocomplete

@csandman
Copy link

For anyone that has had any interest in my wrapper for react-select, I made it into an NPM package. You can find it here: https://www.npmjs.com/package/chakra-react-select

@emvictor
Copy link

emvictor commented Oct 26, 2021

@csandman My team and I are using your wrapper in our project. Any hints on testing it with jest/enzyme? It's actually a component with parts of your code from codesandbox

@csandman
Copy link

@emvictor sorry, can't really help you there, I've never done a lot of testing. I've only used jest in one project and I never got that far with it.

@csandman
Copy link

There have been some major improvements in version 2 and version 3 of my chakra-react-select package, allowing for a fully customizable style system, and the native typescript support added in react-select@5. So if my component didn't feel customizable enough at first, or you had issues implementing it in a TypeScript project, I highly recommend giving it a second chance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: API discussion 💡 It's just a idea worth looking into, but doesn't mean it's priority.
Projects
None yet
Development

No branches or pull requests