Shortcut recorder
Record key combinations into key caps, with conflict warnings, Kbd, and a searchable cheatsheet.
inputsnew
Preview
Shortcut recorder preview
Live · keyboard ready
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
Live · keyboard ready
Open command menu
Click the field, then press your keys.
keyboard-settings-record-a-custom-shortcut-and-show-it-back-to-the-user-.tsxtsx
"use client";
import { useState } from "react";
import { ShortcutRecorder } from "@/components/manicat/shortcut-recorder/shortcut-recorder";
export function ShortcutRecorderSettingsExample() {
const [shortcut, setShortcut] = useState<string | null>(null);
return (
<div className="grid w-full max-w-sm gap-3">
<ShortcutRecorder label="Open command menu" value={shortcut} onValueChange={setShortcut} />
<p className="text-sm text-(color:--text-muted)">{shortcut ? `Saved: ${shortcut}` : "Click the field, then press your keys."}</p>
</div>
);
}
Keyboard interactions
| Keys | Action |
|---|---|
| Enter / Space | Starts recording. |
| Any combination (while recording) | Records it; held modifiers show as caps as you build the chord. |
| Escape (while recording) | Cancels recording. |
| Backspace / Delete | 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. |
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.