Shortcut recorder

Record key combinations into key caps, with conflict warnings, Kbd, and a searchable cheatsheet.

pnpm dlx shadcn@latest add @uiarc/shortcut-recorder
Live · keyboard ready

Shortcuts

Open command menu
Create issue
Toggle sidebar

Press here to open the command menu

Workspace

  • Open command menu
  • Create issue
  • Toggle sidebar

Navigation

  • Go to inbox
  • Go to projects
  • Search everything

Editing

  • Bold
  • Insert link
  • Save draft
  • 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-recorder

Adds 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:

example.tsx
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.

PropTypeDefaultDescription
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.

PropTypeDefaultDescription
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.

PropTypeDefaultDescription
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.

PropTypeDefaultDescription
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.

PropTypeDefaultDescription
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.