Input.Select
StorybookGeneral Info
There is so much in place when talking about Select component aka Dropdown. So much different use-cases, different visuals, different behaviours.
User stories:
- When user clicks (or using the keyboard) on some trigger area, some list of items appears
- When user clicks outside, list hides
- When user hovers/changing focus on items in list, they appears focused
- When user presses up/down, the next/previous list item gets highlighted/focused
- When user clicks an item in the list, different things can happen:
- If the item was selected and this is single select component, do nothing
- If the item was selected and this is multi select component, unselect the item
- If the item was not selected before and this is single select component, select the item, close the Dropdown
- If the item was not selected before and this is multi select component, select the item
Contexts (where the component can live):
- Inside a form
- Standalone component
One component simply can't deal with all that complexity. Or can it?
Architecture
- OnChange and value
- Customizable reducer (inner behavior)
- Customizable renderers (visuals)
OnChange and value
value of the Input.Select is always an array of objects, which corresponds to the options
you provided to the component. The onChange will be called with the new value, again, an array of selected options.
This allows to have the same api for multi- and single- selects.
Behavior:
To be able to manage that complexity, the reducer pattern is used in this component.
Everything is managed through 1 reducer, which is available through Input.Select.defaults.reducer
.
Also, default initialState is available through Input.Select.defaults.initialState
.
You can easily redefine this reducer, for example to do multiselect:
(Pay attention that in this example SelectedValue renderer is still showing only first selected value, you will need to redefine that)Renderers:
You can redefine SelectedValue
, List
and ListItem
renderers using
components
prop.
Every renderer has type:
(props, ref) => JSX.Element;
⚠️ You must assign ref to the corresponding node, otherwise you will lose focusing feature
Example:
You can also hide FormField with
noFormField
prop, but then you need to redefine SelectedValue renderer
Example: