# useShortcut

> A React keyboard shortcut hook in mod+k notation: bind shortcuts, match events and show them as ⌘K on a Mac or Ctrl+K elsewhere.

- Type: React hook (Hooks & Utilities)
- Access: Free (the source is open to everyone)
- Version: 1.0.0
- Install: `npx wingo-ui@latest add use-shortcut`
- Docs: https://wingo-ui.com/components/use-shortcut

## Interaction

Press the shortcuts listed in the panel: the matching row lights up and the log says what ran. Type a combo into the playground (mod+k, shift+?, alt+n) to bind it live and see how it reads on Apple devices and everywhere else. Single keys like / stay quiet while you type in the search field; combos with a modifier still work there.

## Installation

```bash
npx wingo-ui@latest add use-shortcut
```

The CLI adds the files, their dependencies and a version record for updates.

With shadcn: `npx shadcn@latest add https://wingo-ui.com/r/use-shortcut.json`

Files:

- `hooks/use-shortcut.ts`

Wingo UI dependencies (installed automatically):

- [useMediaQuery](https://wingo-ui.com/components/use-media-query) ([Markdown](https://wingo-ui.com/components/use-media-query.md))

## Usage

```tsx
import { useRef } from "react"
import { useShortcut, useShortcutLabel } from "@/hooks/use-shortcut"

export function SearchField() {
  const input = useRef<HTMLInputElement>(null)
  const label = useShortcutLabel("/")

  // a bare "/" is ignored while someone types in another field
  useShortcut("/", () => input.current?.focus())
  useShortcut("mod+k", () => input.current?.focus())

  return (
    <label className="flex items-center gap-2">
      <input ref={input} placeholder="Search listings" aria-keyshortcuts={label.aria} />
      <kbd>{label.text}</kbd>
    </label>
  )
}
```

## API

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `shortcut` | `string \| readonly string[] \| null \| undefined \| false` | `"mod+k"` | useShortcut(shortcut, handler, options?): the combo in mod+k notation ("shift+mod+p", "alt+n", "/", "escape"). mod is ⌘ on Apple devices and Ctrl elsewhere. Pass an array for alternatives; null, "" or false binds nothing, so a component can take a shortcut prop its caller clears. |
| `handler` | `(event: KeyboardEvent) => void` |  | Runs when the shortcut is pressed. It may change on every render; the listener is not re-added. |
| `enabled?` | `boolean` | `true` | Turns the binding off without unmounting, for example while a panel is closed. |
| `allowInInputs?` | `boolean` |  | Fire while focus is in a text field. By default only combos with ctrl, meta, mod or alt do, so a bare / or ? never steals a keystroke from someone typing. |
| `preventDefault?` | `boolean` | `true` | Calls event.preventDefault() when the shortcut fires, so mod+s does not also open the browser's save dialog. |
| `repeat?` | `boolean` | `false` | Fire again while the key is held down. |
| `capture?` | `boolean` | `false` | Listen in the capture phase, before handlers inside the page. |

## Parts

### useShortcutLabel (hook)

The display form for the current device: keys ["⇧", "⌘", "P"] for separate key caps, text "⇧⌘P" (Ctrl+Shift+P elsewhere) for menus, aria for aria-keyshortcuts. Renders the non-Apple form on the server, then swaps. Signature: (shortcut: string | null | undefined) => { keys: string[]; text: string; aria: string | undefined }.

### formatShortcut (function)

The same labels outside React, for a given platform. Signature: (shortcut: string, apple: boolean) => string[].

### formatShortcutText (function)

The same labels outside React, for a given platform. Signature: string.

### matchesShortcut (function)

True when a keyboard event (DOM or React) is exactly this combo. Falls back to the physical key when the layout types a non-Latin character, so mod+k also works on a Romanian or Cyrillic layout and with Option held on a Mac. Signature: (event: ShortcutEvent, shortcut: string | ParsedShortcut, apple?: boolean) => boolean.

### parseShortcut (function)

The parsed combo (cached), the value for aria-keyshortcuts, and whether focus sits in an input, textarea, select or contenteditable element. Signature: (shortcut: string) => ParsedShortcut | null.

### ariaKeyShortcuts (function)

The parsed combo (cached), the value for aria-keyshortcuts, and whether focus sits in an input, textarea, select or contenteditable element. Signature: (shortcut, apple) => string | undefined.

### isTypingTarget (function)

The parsed combo (cached), the value for aria-keyshortcuts, and whether focus sits in an input, textarea, select or contenteditable element. Signature: (target) => boolean.

### UseShortcutOptions (type)

The options object: enabled, allowInInputs, preventDefault, repeat and capture.

### ShortcutLabel (type)

What useShortcutLabel returns: { keys: string[]; text: string; aria: string | undefined }.

### ParsedShortcut (type)

What parseShortcut returns: the key plus mod, ctrl, meta, alt and shift flags.

### ShortcutEvent (type)

The keyboard event fields matchesShortcut reads: key, code and the modifier flags.

## Examples

- **Keyboard list navigation**: j / k or the arrows move through an inbox and Enter opens it, bound only while the list has focus.
- **Send with ⌘ Enter**: A modified combo fires inside the textarea, so the comment sends without leaving the keyboard.

## See also

- [Kbd](https://wingo-ui.com/components/kbd) ([Markdown](https://wingo-ui.com/components/kbd.md))
- [Shortcuts Dialog](https://wingo-ui.com/components/shortcuts-dialog) ([Markdown](https://wingo-ui.com/components/shortcuts-dialog.md))
- [Command Menu](https://wingo-ui.com/components/command-menu) ([Markdown](https://wingo-ui.com/components/command-menu.md))
- [useLongPress](https://wingo-ui.com/components/use-long-press) ([Markdown](https://wingo-ui.com/components/use-long-press.md))
- [useMediaQuery](https://wingo-ui.com/components/use-media-query) ([Markdown](https://wingo-ui.com/components/use-media-query.md))

---

Canonical: https://wingo-ui.com/components/use-shortcut
More components: https://wingo-ui.com/components · Index for agents: https://wingo-ui.com/llms.txt
