Downshift

repository·master·Indexed 11 days ago

https://github.com/downshift-js/downshift

A 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.

Tokens
30.1K
Snippets
63
Records
128
Agent score
95%

What's inside Downshift

  1. Overview of Downshift Hooks

    master
    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.
  2. Overview of Downshift solutions

    master

    Downshift provides two main ways to build accessible autocomplete, combobox, or select components:

    1. 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.
    2. 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.

  3. What is useMultipleSelection?

    master

    useMultipleSelection is a React hook designed to manage the stateful logic for accessible multiple selection dropdowns (either a select or a combobox).

    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-live messages for item removal.

    It is intended to be used alongside other hooks like useCombobox or useSelect to provide a complete multiple-selection experience.

  4. Understand default event handlers in useCombobox

    master

    Downshift 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 highlightedIndex through 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 inputValue based 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 (inputValue becomes "" and selectedItem becomes null).
    • 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.
    • MouseLeave: Clears the highlightedIndex.

    Item

    • Click: Selects the item, closes the menu, and moves focus to the toggle button (unless defaultIsOpen is true).
    • MouseOver: Highlights the item.
  5. Use Control Props to manage Downshift state

    master

    Downshift 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).
  6. Control useTagGroup state using Control Props

    master

    By default, useTagGroup manages its own state for items and activeIndex. 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 via onStateChange or other handlers to keep the UI in sync.

  7. How the Downshift children function works

    master

    The Downshift component uses a render prop pattern via its children function. This function receives a downshift object 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>
    )
  8. Use prop getters with useTagGroup

    master

    Prop 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: getTagProps and getTagRemoveProps are 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 return null before using the result; instead, filter your items first.

    // Correct way to use impure prop getters
    items
      .filter(shouldRenderItem)
      .map(item => <div {...getTagProps({item})} />)
  9. Use prop getters to manage accessibility and rendering

    master

    Downshift 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) } })

  10. Control the state of useMultipleSelection

    master

    By default, Downshift manages its own internal state for selectedItems and activeIndex. 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 the onStateChange handler or other state management tools like Redux or React Router.

  11. How useTagGroup works

    master

    The useTagGroup hook 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), and getTagRemoveProps (for the remove button within a tag).
    • Actions: Functions like addItem to programmatically add tags.
    • State: Current state values like items and activeIndex.

    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']})
  12. How prop getters work in useCombobox

    master

    Prop 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 refKey option to specify which prop is used to forward the ref (defaults to ref).

    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 an id used 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.