Downshift is a set of primitives to build simple, flexible, WAI-ARIA compliant React autocomplete, combobox or select dropdown components. It provides both a traditional render prop class component and modern React hooks for maximum flexibility and control over your UI components while maintaining accessibility standards.
npm install downshiftimport Downshift, { useSelect, useCombobox, useMultipleSelection, resetIdCounter } from "downshift";For CommonJS:
const Downshift = require("downshift");
const { useSelect, useCombobox, useMultipleSelection, resetIdCounter } = require("downshift");import { useSelect } from "downshift";
function SelectExample() {
const items = ['apple', 'pear', 'orange', 'grape', 'banana'];
const {
isOpen,
selectedItem,
getToggleButtonProps,
getLabelProps,
getMenuProps,
highlightedIndex,
getItemProps,
} = useSelect({ items });
return (
<div>
<label {...getLabelProps()}>Choose a fruit:</label>
<button type="button" {...getToggleButtonProps()}>
{selectedItem || 'Select item'}
</button>
<ul {...getMenuProps()}>
{isOpen &&
items.map((item, index) => (
<li
style={
highlightedIndex === index ? { backgroundColor: '#bde4ff' } : {}
}
key={`${item}${index}`}
{...getItemProps({ item, index })}
>
{item}
</li>
))}
</ul>
</div>
);
}Downshift is built around several key design patterns:
Hook for building accessible select/dropdown components with full keyboard navigation and ARIA compliance.
function useSelect<Item>(props: UseSelectProps<Item>): UseSelectReturnValue<Item>;
interface UseSelectProps<Item> {
items: Item[];
itemToString?: (item: Item | null) => string;
onSelectedItemChange?: (changes: UseSelectSelectedItemChange<Item>) => void;
stateReducer?: (
state: UseSelectState<Item>,
actionAndChanges: UseSelectStateChangeOptions<Item>
) => Partial<UseSelectState<Item>>;
// ... additional props
}
interface UseSelectReturnValue<Item> {
isOpen: boolean;
selectedItem: Item | null;
highlightedIndex: number;
getToggleButtonProps: <Options>(options?: UseSelectGetToggleButtonPropsOptions & Options) => UseSelectGetToggleButtonReturnValue;
getLabelProps: <Options>(options?: UseSelectGetLabelPropsOptions & Options) => UseSelectGetLabelPropsReturnValue;
getMenuProps: <Options>(options?: UseSelectGetMenuPropsOptions & Options) => UseSelectGetMenuReturnValue;
getItemProps: <Options>(options: UseSelectGetItemPropsOptions<Item> & Options) => UseSelectGetItemPropsReturnValue;
// ... additional methods and state
}Hook for building accessible combobox/autocomplete components with input field and filtering capabilities.
function useCombobox<Item>(props: UseComboboxProps<Item>): UseComboboxReturnValue<Item>;
interface UseComboboxProps<Item> {
items: Item[];
itemToString?: (item: Item | null) => string;
inputValue?: string;
onInputValueChange?: (changes: UseComboboxInputValueChange<Item>) => void;
onSelectedItemChange?: (changes: UseComboboxSelectedItemChange<Item>) => void;
stateReducer?: (
state: UseComboboxState<Item>,
actionAndChanges: UseComboboxStateChangeOptions<Item>
) => Partial<UseComboboxState<Item>>;
// ... additional props
}
interface UseComboboxReturnValue<Item> {
isOpen: boolean;
selectedItem: Item | null;
highlightedIndex: number;
inputValue: string;
getInputProps: <Options>(options?: UseComboboxGetInputPropsOptions & Options) => UseComboboxGetInputPropsReturnValue;
getToggleButtonProps: <Options>(options?: UseComboboxGetToggleButtonPropsOptions & Options) => UseComboboxGetToggleButtonPropsReturnValue;
// ... additional methods and state
}Hook for managing multiple item selection state, designed to compose with other downshift hooks.
function useMultipleSelection<Item>(
props?: UseMultipleSelectionProps<Item>
): UseMultipleSelectionReturnValue<Item>;
interface UseMultipleSelectionProps<Item> {
selectedItems?: Item[];
onSelectedItemsChange?: (changes: UseMultipleSelectionSelectedItemsChange<Item>) => void;
stateReducer?: (
state: UseMultipleSelectionState<Item>,
actionAndChanges: UseMultipleSelectionStateChangeOptions<Item>
) => Partial<UseMultipleSelectionState<Item>>;
// ... additional props
}
interface UseMultipleSelectionReturnValue<Item> {
selectedItems: Item[];
activeIndex: number;
addSelectedItem: (item: Item) => void;
removeSelectedItem: (item: Item) => void;
setSelectedItems: (items: Item[]) => void;
getSelectedItemProps: <Options>(options: UseMultipleSelectionGetSelectedItemPropsOptions<Item> & Options) => UseMultipleSelectionGetSelectedItemReturnValue;
getDropdownProps: <Options>(options?: UseMultipleSelectionGetDropdownPropsOptions & Options) => UseMultipleSelectionGetDropdownReturnValue;
}Original render prop-based component for backwards compatibility and advanced use cases.
class Downshift<Item = any> extends React.Component<DownshiftProps<Item>> {
static stateChangeTypes: StateChangeTypes;
}
interface DownshiftProps<Item> {
children?: (options: ControllerStateAndHelpers<Item>) => React.ReactNode;
itemToString?: (item: Item | null) => string;
onChange?: (selectedItem: Item | null, stateAndHelpers: ControllerStateAndHelpers<Item>) => void;
stateReducer?: (
state: DownshiftState<Item>,
changes: StateChangeOptions<Item>
) => Partial<StateChangeOptions<Item>>;
// ... additional props
}interface Environment {
addEventListener: typeof window.addEventListener;
removeEventListener: typeof window.removeEventListener;
document: Document;
Node: typeof window.Node;
}
// State change types for useSelect
enum UseSelectStateChangeTypes {
ToggleButtonClick = '__togglebutton_click__',
ToggleButtonKeyDownArrowDown = '__togglebutton_keydown_arrow_down__',
ItemClick = '__item_click__',
FunctionSelectItem = '__function_select_item__',
// ... additional types
}
// State change types for useCombobox
enum UseComboboxStateChangeTypes {
InputKeyDownArrowDown = '__input_keydown_arrow_down__',
InputChange = '__input_change__',
ItemClick = '__item_click__',
FunctionSelectItem = '__function_select_item__',
// ... additional types
}
// State change types for useMultipleSelection
enum UseMultipleSelectionStateChangeTypes {
SelectedItemClick = '__selected_item_click__',
FunctionAddSelectedItem = '__function_add_selected_item__',
FunctionRemoveSelectedItem = '__function_remove_selected_item__',
// ... additional types
}/**
* Resets the internal ID counter used for generating unique IDs.
* Primarily used for server-side rendering to ensure consistent IDs between server and client.
*/
function resetIdCounter(): void;