Shortcut recorder

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

inputsnew
Preview
Shortcut recorder preview
Shortcut

Click, then press keys.

When to use

  • 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 ShortcutKbd or ShortcutKeys.

When not to use

  • Use ShortcutKbd 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.

shadcn CLI

Also installs (1)

  • manicat-foundation
Manual install(+)
registry.jsonjson
{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "shortcut-recorder",
  "type": "registry:ui",
  "title": "Shortcut recorder",
  "description": "Record key combinations into key caps, with conflict warnings, Kbd, and a searchable cheatsheet.",
  "categories": [
    "inputs"
  ],
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "https://manicat.viraza.net/r/manicat-foundation.json"
  ],
  "files": [
    {
      "path": "registry/components/shortcut-recorder/shortcut-recorder.tsx",
      "type": "registry:component",
      "target": "@components/manicat/shortcut-recorder/shortcut-recorder.tsx"
    },
    {
      "path": "registry/components/shortcut-recorder/shortcut-recorder.module.css",
      "type": "registry:component",
      "target": "@components/manicat/shortcut-recorder/shortcut-recorder.module.css"
    }
  ],
  "docs": "Docs and live preview: https://uiarc.dev/components/shortcut-recorder",
  "meta": {
    "tier": "free",
    "kind": "component",
    "docs": "https://manicat.viraza.net/components/shortcut-recorder",
    "markdown": "https://uiarc.dev/components/shortcut-recorder/markdown",
    "tags": [
      "inputs",
      "new"
    ]
  }
}

Usage

Install the component, then copy this into your app. Change the content and the props to fit your screen.

example.tsxtsx
"use client";

import { useState } from "react";
import { ShortcutRecorder } from "@/components/manicat/shortcut-recorder/shortcut-recorder";

export function ShortcutRecorderExample() {
  const [shortcut, setShortcut] = useState<string | null>(null);

  return (
    <div className="grid w-full max-w-sm gap-3">
      <ShortcutRecorder label="Shortcut" value={shortcut} onValueChange={setShortcut} />
      <p className="text-sm text-(color:--text-muted)">{shortcut ? `Recorded: ${shortcut}` : "Click, then press keys."}</p>
    </div>
  );
}

Examples

Real screens rather than isolated props. Switch to Code to copy a whole example into your project.

Keyboard settings Record a custom shortcut and show it back to the user.

Keyboard settings Record a custom shortcut and show it back to the user. preview
Open command menu

Click the field, then press your keys.

Keyboard interactions

KeysAction
Enter / SpaceStarts recording.
Any combination (while recording)Records it; held modifiers show as caps as you build the chord.
Escape (while recording)Cancels recording.
Backspace / DeleteClears 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.

Accessibility

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

Motion

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

Responsive behavior

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

Performance

  • 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

  • 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 ShortcutKbd for inline hints such as in menus or command-palette rows.