Skip to content
Component installs need the registry setup— the Base UI shadcn project, the @vegastack namespace and the Cloudflare Access service token.
VegaStack Design

Kbd

The one keyboard-key chip — deterministic modifier labels resolved by the caller, a keys array, and three inline sizes.

Status
stable
Since
0.1.0
Accessibility pattern
native kbd element

Last updated

CtrlKEsc

Install

Add Kbd from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.

pnpm dlx shadcn@latest add @vegastack/kbd

Usage

import { Kbd, KbdGroup } from '@/components/ui/kbd';

// Single key
<Kbd>⌘</Kbd>

// A combo as an array — each token is its own chip
<Kbd keys={['⌘', 'K']} />;

Anatomy

Kbd is a compound component. Every exported part, with the data-slot it renders (generated from the canonical source):

Kbd — data-slot="kbd"
KbdGroup — data-slot="kbd-group"

Examples

Anatomy

Kbd renders a single <kbd> chip, or — when given a keys array — a row of chips wrapped in a KbdGroup. Compose KbdGroup yourself to mix in non-key content.

<KbdGroup>
  <Kbd>⌘</Kbd>
  <Kbd>K</Kbd>
</KbdGroup>

Combos

Pass a keys array to render a shortcut, or compose individual Kbd chips inside a KbdGroup. Write tokens as mac glyphs; os decides how they render. The default is os="other" (words), so pass os="mac" — or the resolved platform — for the glyphs.

CtrlKCtrlShiftPCtrlEnterCtrlBksp

Sizes

xs, sm, and md — sized to sit inline with text, menus, and tooltips. All three use one type role, text-code-sm; md previously reached the same 12px through text-sm, the same pixel size named twice.

CtrlCtrlCtrl

Platform Labels

Kbd is server-safe and deterministic: it reads no navigator and therefore never guesses the platform. Resolving the platform is the caller's job — run usePlatform() and pass the answer down. os defaults to "other", the same fallback usePlatform reports before hydration, so an unwired chip shows a word every reader understands rather than shipping to a Windows majority.

The rewrite applies whether you pass a keys array or a single string child (Ctrl, Shift, Alt, Ctrl, /Enter, Bksp). On mac the glyph is rendered visually with an sr-only spoken name beside it, because a screen reader announces as "place of interest sign" or skips it entirely.

// The wiring every caller should use
const { os } = usePlatform();
<Kbd keys={["⌘", "K"]} os={os === "mac" ? "mac" : "other"} />;

<Kbd os="mac" keys={['⌘', 'K']} />   {/* ⌘ K */}
<Kbd os="other" keys={['⌘', 'K']} /> {/* Ctrl K (the default) */}

// Single string children are rewritten too
<Kbd os="other">⌘</Kbd>             {/* Ctrl */}

Playground

Change the size and platform to watch the ⌘ glyph swap to Ctrl, then copy the generated JSX.

CommandK
<Kbd keys={['⌘', 'K']} />

API Reference

Kbd

PropTypeDefaultDescription
childrenReact.ReactNodeA single key label — used when keys is not provided.
keysreadonly string[]Explicit key tokens to render. Each token becomes its own <kbd>. Modifier glyphs (, , , , , ) are rewritten to words on non-mac platforms. Takes precedence over children.
os"mac" | "other"'other'Platform label mode. 'other' renders readable Windows/Linux modifier words (Ctrl, Alt, …); 'mac' renders the glyphs (, , …) paired with sr-only spoken names. Defaults to 'other' — the same SSR default usePlatform reports (audit B2-10). Kbd is server-safe and deliberately reads no navigator, so the platform is the CALLER's to resolve: run usePlatform() and pass the result down. An unwired badge then shows a word every reader understands rather than a mac glyph shipped to a Windows majority.
size"md" | "sm" | "xs"'md'Size of the key chip — mirrors the lower end of the shared scale.

Data attributes and CSS variables on Kbd

AttributeValues
data-sizemirrors a prop or state value
data-slot"kbd"

KbdGroup

KbdGroup adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

Data attributes and CSS variables on KbdGroup

AttributeValues
data-slot"kbd-group"

The kbdVariants CVA helper is also exported for advanced styling — call kbdVariants({ size }) to reuse the chip classes (the single size axis: xs | sm | md) on a custom element.

Accessibility

  • Renders a native, non-interactive <kbd> element — the semantic element for keyboard input, so assistive tech announces it as such.
  • The chip is a label, never a control: it does not receive focus and carries no tabindex. Wire the actual shortcut up on the relevant control (e.g. a button or a menu item).
  • Modifier glyphs are rewritten to readable words on non-mac platforms, so a shortcut is never announced as an unfamiliar symbol. On mac the glyph is aria-hidden and an sr-only word (Command, Option, …) carries the accessible name.
  • Kbd is the only key chip in the system: TooltipKbd renders it rather than restyling a second <kbd>, so a shortcut hint reads identically wherever it appears.
KeyBehavior
(none)Kbd is presentational — it has no interactive keyboard behavior.
ContractStates tested
Behaviourdefault
Accessibilitynative-or-base-ui-semantics, browser-accessibility-test
Visualdefault

Do / Don't

Do
Use Kbd to display a shortcut alongside the control it triggers, and resolve os once with usePlatform at the call site.
Don't
Make a Kbd clickable or focusable, or hardcode ⌘ in copy that Windows and Linux users will also read.

On this page