Kbd
A keycap for a keyboard shortcut. Use KbdGroup for a combination — the grouping is semantic, not decorative.
Added 14 October 2026
Grouping changes the meaning
Per the HTML Standard, sibling <kbd> elements mean keys pressed in sequence, while a <kbd> wrapping
<kbd>s means a combination. KbdGroup is that outer <kbd>, so this is not a styling wrapper you can
skip:
<KbdGroup><Kbd>⌘</Kbd><Kbd>K</Kbd></KbdGroup> // press ⌘ and K together
<Kbd>G</Kbd> <Kbd>I</Kbd> // press G, then I
Pick one convention for the + and hold to it. This library’s demos omit it inside a group, because the
group already carries the meaning and the glyphs read fine without it.
aria-label does not work here — and cannot
<kbd> maps to the ARIA generic role, and name-from-author is prohibited for that role. An
aria-label on a Kbd or KbdGroup is specified to be ignored, so it is not a fix, it is a lie in the
source. [a11y]
Consequence: ⌘ (U+2318) and ⇧ (U+21E7) have no reliable screen-reader pronunciation, and you cannot label
your way out of it. Two real options:
- Use words —
Cmd,Shift,Ctrl,Alt. Least clever, most robust, and the right default for anything a user has to act on. - Pair a hidden word with the glyph — the glyph
aria-hidden, a visually hidden word beside it:
<Kbd><span aria-hidden="true">⌘</span><span className="sr-only">Command</span></Kbd>
Reach for the glyph-only form only in dense UI where the shortcut is a reminder rather than instruction.
Where a keycap belongs
- Beside the action it triggers — in a
DropdownMenurow, aTooltip, a command palette row, or inline in a short instruction. - Never as a control. A keycap is a label; it is
pointer-events-noneby design. If it should be clickable it is aButton.
Inside a tooltip the keycap inverts automatically, because the tooltip surface is inverted. That override keys
off different attributes per framework (React on the tooltip’s data-slot, Angular on role="tooltip", which
is what brain emits) — mentioned only so nobody “aligns” them.
Deviation from upstream
The text is text-foreground, not upstream’s text-muted-foreground: on the muted keycap fill that computes
to 3.93:1 in the light theme, and at 12px it needs 4.5:1 (WCAG 1.4.3). A keycap is a label, not secondary text.
Both shadcn and spartan helm fail this pairing; don’t restore it.
font-sans is also deliberate. This library reserves font-mono for machine data — prices, IDs, codes. A
keycap names a physical key, so mono would make Ctrl/Enter read as code.
Never
- A bare glyph keycap in instructional copy — write the word.
aria-labelon a keycap; it is ignored.- Sibling keycaps for a simultaneous shortcut; that means “then”.
- A keycap as a button.