Hotkey
Parse, label, announce and match keyboard shortcuts, with ⌘ on Apple platforms and Ctrl everywhere else.
- Apple
- ⇧⌘K
- Windows and Linux
- Shift+Ctrl+K
- Screen readers
- Shift Command K
- parseHotkey
- [["shift","mod","k"]]
Click outside the field and press Shift Command Kmatched 0×
pnpm dlx shadcn@latest add https://hextaui.com/r/hotkey.jsonAdds the utility and anything it depends on to your project.
Copy and paste the following code into your project.
lib/hotkey.ts Update the import paths to match your project setup.
Write each shortcut once, as a string, and use the same string to display it, announce it and match it. mod means ⌘ on Apple platforms and Ctrl everywhere else. That's almost always what you want, since Ctrl+K on a Mac and ⌘K on Windows both feel wrong.
Keys are separated by + and are case-insensitive. Named keys use the lowercase KeyboardEvent.key value, like enter, tab, pageup or f5. Use space for the space bar.
parseHotkey returns one array per chord, with aliases resolved and modifiers sorted into Apple's order: Control, Option, Shift, Command. Every label built from it reads in the order people expect to see it.
Apple platforms use symbols with no separator, the way menus show them. Windows and Linux use words joined by +. Symbols are hard to read aloud, so spokenKey gives the name a screen reader should announce instead. <Kbd keys> shows the symbol and puts the spoken name in visually hidden text.
useIsApple() picks the platform. It returns true on the server and during hydration, then the real answer, so a Windows visitor briefly sees ⌘ before Ctrl instead of getting a hydration error.
Shortcut listener
matchesHotkey checks a keydown event against a hotkey. Modifiers must match exactly, so mod+b doesn't fire for mod+shift+b.
- BoldCommand B
- ItalicCommand I
- StrikethroughShift Command X
Press a shortcut
- Letters and digits also match by physical key, so
alt+kworks on a Mac, where Option+K types˚. - Shifted letters match:
shift+kmatches theKthat Shift produces. - It matches one chord. For sequences like
g i, track the previous chord yourself. - Skip shortcuts without modifiers while the focus is in a text field, so typing a letter never triggers a command.
| Export | Description |
|---|---|
parseHotkey(hotkey) | string[][]: one array per chord, with aliases resolved and modifiers sorted. |
formatHotkey(hotkey, apple) | The label for one chord, such as ⇧⌘K or Shift+Ctrl+K. |
keyLabel(key, apple) | The visible label for one key name. |
spokenKey(key, apple) | The name a screen reader should announce for one key. |
matchesHotkey(event, hotkey) | Whether a KeyboardEvent matches one chord, with exact modifiers. |
isApplePlatform() | Reads navigator.platform. true on the server. |
useIsApple() | isApplePlatform as a hydration-safe hook. |
Kbd and Command.