Downshift
repository·master·Indexed 11 days ago
https://github.com/downshift-js/downshiftA set of primitives to build simple, flexible, and WAI-ARIA compliant React autocomplete, combobox, or select dropdown components. It offers a recommended set of hooks (useSelect, useCombobox, useTagGroup) supporting W3C ARIA 1.2 patterns, as well as a render-prop component for flexible UI control.
What's inside Downshift
- Downshift provides a set of React hooks designed to build simple, flexible, and WAI-ARIA compliant dropdown components. These hooks allow you to create fully accessible widgets (like selects, comboboxes, and tag groups) without being constrained by a specific UI library.
Overview of Downshift solutions
masterDownshift provides two main ways to build accessible autocomplete, combobox, or select components:
Hooks (Recommended): A set of React hooks that provide stateful logic. These are actively maintained and support the latest W3C ARIA 1.2 combobox patterns.
useSelect: For custom select components.useCombobox: For combobox or autocomplete inputs.useTagGroup: For tag groups or multiple selection components.
Downshift Component: A render-prop component that provides logic via a function child. While powerful and flexible, it does not support the latest ARIA patterns and is slated for eventual removal in favor of the hooks.
What is useMultipleSelection?
masteruseMultipleSelectionis a React hook designed to manage the stateful logic for accessible multiple selection dropdowns (either aselector acombobox).It handles:
- Adding and removing items from the selection.
- Navigating between selected items and the dropdown.
- ARIA attributes and event listeners via getter props.
- Accessibility features like
aria-livemessages for item removal.
It is intended to be used alongside other hooks like
useComboboxoruseSelectto provide a complete multiple-selection experience.Understand default event handlers in useCombobox
masterDownshift provides implicit event handlers for various UI elements to ensure accessibility and standard autocomplete behavior. Many of these handlers call
event.preventDefault()to manage focus and state automatically.Toggle Button
- Click / Enter / Space: Toggles the menu visibility. If opening, it moves focus to the input and highlights the currently selected item if one exists.
Input
- ArrowDown / ArrowUp: Cycles
highlightedIndexthrough the list (wraps around at boundaries). - Alt+ArrowDown: Opens the menu without highlighting an item.
- Alt+ArrowUp: Closes the menu and selects the currently highlighted item.
- CharacterKey: Updates
inputValuebased on input. - End / Home: Highlights the last or first item in the list.
- PageUp / PageDown: Moves highlight by 10 positions.
- Enter: Selects the highlighted item and closes the menu.
- Escape: Closes the menu. If the menu was closed, it clears the selection (
inputValuebecomes""andselectedItembecomesnull). - Click: Toggles menu visibility.
- Blur (Tab / Shift+Tab): Closes the menu and selects the highlighted item (if any).
- Blur (Mouse click outside): Closes the menu without selecting anything.
Menu
- MouseLeave: Clears the
highlightedIndex.
Item
- Click: Selects the item, closes the menu, and moves focus to the toggle button (unless
defaultIsOpenis true). - MouseOver: Highlights the item.
Use Control Props to manage Downshift state
masterDownshift allows you to take full control of its state by passing specific props. When these are provided, Downshift treats them as the source of truth (the "controlled" pattern).
The following are control props:
highlightedIndex: The index that should be highlighted.inputValue: The value the input should have.isOpen: Whether the menu should be open or closed.selectedItem: The currently selected item (can be a single item or an array).
Control useTagGroup state using Control Props
masterBy default,
useTagGroupmanages its own state foritemsandactiveIndex. However, you can take full control of this state by passing these values as props. This is useful when integrating with external state management like Redux or React Router.Controlled Props:
items: The items part of the tag group.activeIndex: The index of the item that should be active/focused.
When these props are provided (
!== undefined), Downshift will use your values instead of its internal state. You are responsible for updating these values viaonStateChangeor other handlers to keep the UI in sync.How the Downshift children function works
masterThe
Downshiftcomponent uses a render prop pattern via itschildrenfunction. This function receives adownshiftobject containing state, prop getters, and actions, allowing you to render your own UI while Downshift manages the logic and accessibility.const ui = ( <Downshift> {downshift => ( // Use downshift utilities and state here <div>{/* your JSX */}</div> )} </Downshift> )const ui = ( <Downshift> {downshift => ( // use downshift utilities and state here, like downshift.isOpen, // downshift.getInputProps, etc. <div>{/* more jsx here */}</div> )} </Downshift> )Use prop getters with useTagGroup
masterProp getters are functions that return ARIA attributes and event handlers. You should apply them to your elements to ensure accessibility. It is recommended to pass your own props into the getter function to avoid overriding or being overridden.
Important:
getTagPropsandgetTagRemovePropsare impure functions. They should only be called when you are actually applying the props to an item. Do not call them inside a.map()loop if you might returnnullbefore using the result; instead, filter your items first.// Correct way to use impure prop getters items .filter(shouldRenderItem) .map(item => <div {...getTagProps({item})} />)Use prop getters to manage accessibility and rendering
masterDownshift provides "prop getters" to apply necessary ARIA attributes and event handlers to your elements. To ensure accessibility and prevent your own props from being overridden, always spread the returned props onto your elements and pass your custom props as an argument to the getter.
Example:
getInputProps({ onKeyUp(event) { console.log(event) } })Control the state of useMultipleSelection
masterBy default, Downshift manages its own internal state for
selectedItemsandactiveIndex. However, you can switch to a controlled component pattern by passing these state values as props.When you provide a prop like
selectedItems={myState}, Downshift will use your value instead of its internal state. You are then responsible for updating that state, typically by using theonStateChangehandler or other state management tools like Redux or React Router.How useTagGroup works
masterThe
useTagGrouphook manages the stateful logic and accessibility requirements for a tag group component. It follows Downshift's 'getter props' pattern, where the hook returns functions that, when called, return a set of ARIA attributes and event listeners.To implement a tag group, you destructure the following from the hook:
- Prop Getters:
getTagGroupProps(for the container),getTagProps(for individual tags), andgetTagRemoveProps(for the remove button within a tag). - Actions: Functions like
addItemto programmatically add tags. - State: Current state values like
itemsandactiveIndex.
This approach ensures that features like item removal, selection, keyboard navigation (left/right arrows), and screen reader support are implemented out-of-the-box.
import {useTagGroup} from 'downshift' const { addItem, getTagProps, getTagRemoveProps, getTagGroupProps, items, activeIndex, } = useTagGroup({initialItems: ['Red', 'Blue']})- Prop Getters:
How prop getters work in useCombobox
masterProp getters are functions that return an object of props (including critical
aria-attributes for accessibility) that you should apply to your rendered elements.Best Practices:
- Always use the prop getters to ensure accessibility.
- Apply all your own props inside the getter function to prevent them from being overridden. For example:
getToggleButtonProps({onKeyDown(event) { ... }}). - For composite components, use the
refKeyoption to specify which prop is used to forward the ref (defaults toref).
Available Prop Getters:
getToggleButtonProps: Apply to the menu toggle button.getItemProps: Apply to each individual menu item.getLabelProps: Apply to the<label>element. This generates anidused to link the label to the toggle button and menu.getMenuProps: Apply to the container of your list (e.g.,<ul>or<div>).getInputProps: Apply to the<input>element.