useKeyActions

A hook for handling keyboard actions with customizable key bindings and modifiers.

Made by raouf.codes
Edit on GitHub

Overview

The useKeyActions hook provides a declarative way to handle keyboard events with support for multiple key bindings, modifier keys, and scoped focus management. It powers the keyboard navigation in components like FloatingDock and Tabs.

Installation

Usage

Basic

import { useKeyActions } from '@/hooks/use-key-actions';

function SearchInput() {
  const inputRef = useRef<HTMLInputElement>(null);

  const handleKeyDown = useKeyActions([
    {
      keys: ['Escape'],
      action: () => {
        inputRef.current?.blur();
      },
    },
    {
      keys: ['Enter'],
      action: () => {
        // Submit search
      },
    },
  ]);

  return (
    <input ref={inputRef} onKeyDown={handleKeyDown} placeholder="Search..." />
  );
}

With Modifier Keys

const handleKeyDown = useKeyActions([
  {
    keys: ['s'],
    modifiers: { meta: true }, // Cmd+S on Mac
    action: () => {
      saveDocument();
    },
  },
  {
    keys: ['z'],
    modifiers: { meta: true, shift: true }, // Cmd+Shift+Z
    action: () => {
      redo();
    },
  },
]);

Scoped to a Container

function NavigationList() {
  const containerRef = useRef<HTMLUListElement>(null);

  const handleKeyDown = useKeyActions(
    [
      {
        keys: ['ArrowDown'],
        action: (e) => {
          // Move focus to next item
        },
      },
      {
        keys: ['ArrowUp'],
        action: (e) => {
          // Move focus to previous item
        },
      },
    ],
    containerRef, // Only handle events when focus is within this container
  );

  return (
    <ul ref={containerRef} onKeyDown={handleKeyDown}>
      <li tabIndex={0}>Item 1</li>
      <li tabIndex={-1}>Item 2</li>
      <li tabIndex={-1}>Item 3</li>
    </ul>
  );
}

Conditional Enabling

function Modal({ isOpen }: { isOpen: boolean }) {
  const handleKeyDown = useKeyActions(
    [
      {
        keys: ['Escape'],
        action: () => closeModal(),
      },
    ],
    undefined,
    isOpen, // Only handle events when modal is open
  );

  return <div onKeyDown={handleKeyDown}>{/* Modal content */}</div>;
}

Click on Match

const handleKeyDown = useKeyActions([
  {
    keys: ['Enter', ' '],
    action: () => {},
    clickOnMatch: true, // Programmatically click the target element
  },
]);

API Reference

useKeyActions

function useKeyActions(
  keyActions: KeyAction[],
  activeRef?: React.RefObject<HTMLElement | null>,
  enabled?: boolean,
): (e: React.KeyboardEvent<HTMLElement>) => void;
PropTypeDefault
keyActions
KeyAction[]
-
activeRef?
React.RefObject<HTMLElement | null>
-
enabled?
boolean
true
returns?
(e: React.KeyboardEvent<HTMLElement>) => void
-

KeyAction

PropTypeDefault
keys
string[]
-
action
function
-
modifiers?
Modifiers
-
clickOnMatch?
boolean
false

Modifiers

PropTypeDefault
ctrl?
boolean
-
alt?
boolean
-
shift?
boolean
-
meta?
boolean
-

Helper Functions

modifiersMatch

Utility function to check if an event's modifier keys match the expected modifiers.

import { modifiersMatch } from '@/hooks/use-key-actions';

function handleKeyDown(e: React.KeyboardEvent) {
  if (e.key === 's' && modifiersMatch(e, { meta: true })) {
    // Handle Cmd+S
  }
}

Features

  • Multiple key bindings — Define multiple keys that trigger the same action
  • Modifier support — Handle Ctrl, Alt, Shift, and Meta (Cmd) key combinations
  • Scoped handling — Optionally scope key handling to a specific container
  • Conditional enabling — Dynamically enable/disable key handling
  • Click simulation — Optionally click the target element after action
  • Memoized handler — Returns a stable callback reference

Credits

  • Inspired by keyboard handling patterns from accessible component libraries

Built by raouf.codes. The source code is available on GitHub.

Last updated: 2/27/2026

On this page