Shortcut recorder
Record key combinations into key caps, with conflict warnings, Kbd, and a searchable cheatsheet.
pnpm dlx shadcn@latest add @uiarc/shortcut-recorderShortcuts
Press ⌘K here to open the command menu
Workspace
- Open command menu⌘K
- Create issue⌥N
- Toggle sidebar⌘.
Navigation
- Go to inbox⌥1
- Go to projects⌥2
- Search everything⇧⌘F
Editing
- Bold⌘B
- Insert link⇧⌘L
- Save draft⌘S
- Settings pages where people remap keyboard shortcuts.
- A keyboard shortcut cheatsheet or help dialog, with ShortcutList.
- Inline key hints in menus, tooltips, and docs, with Kbd or ShortcutKeys.
- Use Kbd alone when shortcuts are fixed and only need to be shown.
- Use command-palette to let people run actions by name rather than bind keys.
- Avoid it on touch-only products where no hardware keyboard is expected.
Installation
Add Shortcut recorder with the shadcn CLI, or copy the source by hand.
pnpm dlx shadcn@latest add @uiarc/shortcut-recorderAdds the component and its local dependencies, and installs motion, lucide-react. First time? Add the @uiarc registry to components.json, or use the full URL:
import { useEffect, useState } from "react";import { ShortcutRecorder, matchesShortcut, usePlatform } from "@/registry/components/shortcut-recorder/shortcut-recorder"; export function SearchShortcut() { const platform = usePlatform(); const [shortcut, setShortcut] = useState<string | null>("mod+k"); useEffect(() => { if (!shortcut) return; const onKey = (event: KeyboardEvent) => { if (matchesShortcut(event, shortcut, platform)) { event.preventDefault(); openSearch(); } }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [platform, shortcut]); return ( <ShortcutRecorder label="Open search" value={shortcut} onValueChange={setShortcut} resetValue="mod+k" bindings={[{ shortcut: "mod+p", label: "Print" }]} /> );}API reference
5 parts. The first is the root.
ShortcutRecorder
A field that records a keyboard shortcut, lights held keys as caps, and asks before taking a combination already in use.
labelRequiredstring–Field label.hideLabelbooleanfalseKeeps the label for screen readers only.valuestring | null–Controlled shortcut, such as "mod+shift+k". mod is Command on Apple platforms and Ctrl elsewhere.defaultValuestring | nullnullStarting shortcut when uncontrolled.onValueChange(value: string | null, details: { replaced?: ShortcutBinding }) => void–Called with the new shortcut; replaced is the binding it was taken from after Use anyway.resetValuestring | null–What the reset button restores. Defaults to defaultValue.bindingsShortcutBinding[][]Shortcuts already in use: { shortcut, label }. Recording one asks before taking it.warnReservedbooleantrueAlso warn about combinations the browser or system keeps, such as ⌘W and ⌘C.requireModifierbooleantrueRequire ⌘, Ctrl, or ⌥. Function keys are always allowed.platform"mac" | "other"–Overrides the detected platform.placeholderstring"Record shortcut"Shown when there is no shortcut.descriptionstring–Hint under the field.disabledbooleanfalseDisables recording.idstring–Id of the recorder button.classNamestring–Class on the root.ShortcutList
A searchable, grouped shortcut cheatsheet. Holding a modifier lights its caps and fades rows that do not use it.
groupsRequiredShortcutListGroup[]–Groups: { label, items: { label, shortcut, keywords? }[] }.labelstring"Keyboard shortcuts"Accessible name of the list.searchablebooleantrueShows the search field.searchPlaceholderstring"Search shortcuts"Search placeholder and label.highlightPressedbooleantrueLight caps as keys are held and fade rows that do not use the held modifiers.platform"mac" | "other"–Overrides the detected platform.classNamestring–Class on the root.ShortcutKeys
A shortcut drawn as key caps in platform order, with a spoken label.
shortcutRequiredstring–Such as "mod+k".platform"mac" | "other"–Overrides the detected platform.pressedReadonlySet<string>–Held key ids from usePressedKeys; matching caps light up.size"sm" | "md""md"Cap size.classNamestring–Class on the wrapper.Kbd
A single key cap for inline copy and menus.
childrenRequiredReactNode–The key label.pressedbooleanfalseDraws the key pushed down and lit.size"sm" | "md""md"Cap size....propsHTMLAttributes<HTMLElement>–Forwarded to the kbd element.matchesShortcut / formatShortcut / usePlatform / usePressedKeys
Helpers: test a keydown against a stored shortcut, format it as "⌘⇧K" or "Ctrl+Shift+K" with a spoken form, read the platform, and track held keys.
event, shortcut, platformRequiredKeyboardEvent, string, Platform–matchesShortcut returns true when the keydown is this shortcut.shortcut, platformRequiredstring, Platform–formatShortcut returns { text, spoken }.overridePlatform–usePlatform(override?) returns "mac" or "other"; the server assumes mac.enabledbooleantrueusePressedKeys(enabled?) returns the set of held key ids.- EnterorSpace
- Starts recording.
- Any combination (while recording)
- Records it; held modifiers show as caps as you build the chord.
- Escape (while recording)
- Cancels recording.
- BackspaceorDelete
- Clears the shortcut, while recording or while the field has focus.
- Tab (while recording)
- Stops recording and moves on without recording Tab.
- Escape (in list search)
- Clears the ShortcutList search.
- The recorder is a button with aria-pressed while recording, named by the label plus the spoken shortcut, such as "Command Shift K".
- Recording, results, conflicts, and clears are announced through a polite live region; the message row is linked with aria-describedby.
- Key caps are aria-hidden inside the recorder; ShortcutKeys uses role="img" with a spoken aria-label.
- Conflicts offer Use anyway and Cancel as real buttons, and focus returns to the recorder after either.
- Caps pop in with a small scale and blur, staggered when a finished shortcut settles, and slide on a snappy layout spring as the chord changes.
- A recording dot pulses; the message row opens on a height spring.
- In ShortcutList, groups and rows collapse on a height spring as search filters them.
- Reduced motion removes the scale, stagger, layout slide, and height springs; caps and messages fade.
- ShortcutList is a container with a query at 520px that puts groups in two columns; below that they stack.
- The recorder keeps a fixed height and caps wrap within it; hover styles apply only on fine pointers.
- usePressedKeys adds window keydown and keyup listeners only while enabled; turn off highlightPressed for lists that do not need it.
- ShortcutList filters on every keystroke by building token strings per row; it suits lists of a few hundred shortcuts.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Store shortcuts as normalized strings with mod ("mod+shift+k"); they read as ⌘ on Mac and Ctrl elsewhere without a second binding.
- Run bound actions with matchesShortcut in a keydown listener; it compares physical keys, so ⌥K matches "alt+k" rather than "˚".
- Pass every existing binding in bindings, and use details.replaced from onValueChange to unbind the old owner after Use anyway.
- Use ShortcutList for a help sheet and Kbd for inline hints such as in menus or command-palette rows.
The full library index for assistants is at /llms.txt.