useKeyboard

Handles keyboard interactions for a focusable element.

    import React from 'react';
    import {useKeyboard} from 'react-aria/useKeyboard';
    
    function Example() {
      let [events, setEvents] = React.useState<string[]>([]);
      let {keyboardProps} = useKeyboard({
        onKeyDown: e => setEvents(
          events => [`key down: ${e.key}`, ...events]
        ),
        onKeyUp: e => setEvents(
          events => [`key up: ${e.key}`, ...events]
        )
      });
    
      return (
        <>
          <label htmlFor="example">Example</label>
          <input
            {...keyboardProps}
            id="example" />
          <ul
            style={{
              maxHeight: '200px',
              overflow: 'auto'
            }}>
            {events.map((e, i) => <li key={i}>{e}</li>)}
          </ul>
        </>
      );
    }
    

    Features

    useKeyboard handles keyboard interactions. The only difference from DOM events is that propagation is stopped by default if there is an event handler, unless event.continuePropagation() is called. This provides better modularity by default, so that a parent component doesn't respond to an event that a child already handled. If the child doesn't handle the event (e.g. it was for an unknown key), it can call event.continuePropagation() to allow parents to handle the event.

    Shortcuts

    useKeyboard also accepts a shortcuts prop, which maps shortcut strings to handler functions. Shortcuts combine modifiers and keys with + (e.g. "Mod+s", "Shift+ArrowLeft"). Modifier names are case-insensitive and can appear in any order. Mod means Command on macOS and Control on other platforms. (You can also use dynamic keys to create platform-specific shortcuts. [key + (isMac() ? '+Alt' : '+Control')])

    When a key is pressed, the event is matched against the shortcuts map. If a handler is found, it is called after any onKeyDown handler. Handlers may return:

    • Nothing — the shortcut is handled. Propagation is stopped and the default action is prevented.
    • true or false — shorthand for preventing the default action (true) or allowing the browser default and propagation to continue (false).
    • An object with shouldContinuePropagation and/or shouldPreventDefault for fine-grained control.

    If no shortcut matches, the event is propagated to parent elements.

    Focus the text field and press Mod+S, , or . prevents the cursor from moving. moves the cursor and propagates to the parent. Press any other key to see unmatched events propagate.

      import React from 'react';
      import {useKeyboard} from 'react-aria/useKeyboard';
      
      function Example() {
        let [events, setEvents] = React.useState<string[]>([]);
        let add = (message: string) => setEvents(events => [message, ...events]);
      
        let {keyboardProps: parentProps} = useKeyboard({
          onKeyDown: () => add('parent onKeyDown')
        });
      
        let {keyboardProps: childProps} = useKeyboard({
          shortcuts: {
            'Mod+s': () => add('child shortcut: Mod+s (prevents save dialog)'),
            'ArrowLeft': () => add('child shortcut: ArrowLeft (prevents default, stops propagation)'),
            'ArrowRight': () => {
              add('child shortcut: ArrowRight (allows default, continues propagation)');
              return false;
            }
          },
          onKeyDown: () => add('child onKeyDown')
        });
      
        return (
          <>
            <p>
              Focus the text field and press <kbd>Mod</kbd>+<kbd>S</kbd>, <kbd>←</kbd>,
              or <kbd>→</kbd>. <kbd>←</kbd> prevents the cursor from moving. <kbd>→</kbd> moves the
              cursor and propagates to the parent. Press any other key to see unmatched events propagate.
            </p>
            <div
              {...parentProps}
              style={{
                border: '1px solid gray',
                padding: 16
              }}>
              <label htmlFor="shortcuts-example" style={{display: 'block', marginBottom: 8}}>
                Text field
              </label>
              <input
                {...childProps}
                id="shortcuts-example"
                defaultValue="Move the cursor with arrow keys"
                style={{width: '100%'}} />
            </div>
            <ul
              style={{
                maxHeight: '200px',
                overflow: 'auto'
              }}>
              {events.map((e, i) => <li key={i}>{e}</li>)}
            </ul>
          </>
        );
      }
      

      API

      useKeyboard(props: ):

      KeyboardProps

      NameType
      isDisabledboolean

      Whether the keyboard events should be disabled.

      shortcuts

      Keyboard shortcuts to handle.

      allowRepeatsboolean

      Whether to allow repeating keys. Only affects shortcuts.

      allowComposingboolean

      Whether to allow composing keys. Only affects shortcuts.

      KeyboardResult

      NameType
      keyboardPropsDOMAttributes

      Props to spread onto the target element.