Add this component

npx zentauri-ui add kbd

Accessibility notes

Keyboard accessible by default with semantic markup, visible focus treatment, and tokenized states. Add descriptive labels for icon-only or decorative usage.

Dependency notes

Static imports do not pull framer-motion. Use the animated entry only when you want motion and have framer-motion installed.

Display

Kbd for keyboard shortcut keycaps

Kbd renders keyboard shortcuts as semantic <kbd> keycaps. Pass a single key through children or a multi-key chord through the keys array with an optional separator. It ships sizes, the full Zentauri appearance and gradient system, and an optional animated key press from the kbd/animated entry.

Open command palette+K
EscCtrl+Shift+P+Enter+Tab

Examples

Kbd renders keyboard shortcuts as semantic keycaps. Pass a single key via children, or a chord via the keys array with an optional separator.


Esc

+K

GthenI

+K

Kbd variants playground

Pick an appearance and size to preview the kbd live. Toggle Show output / Show code and the snippet updates to match the selected variant.


Esc+KCtrl+Shift+P

All appearances

Every shipped appearance token at a glance. Click any swatch to load it into the playground above.


Motion: ANIMATED KEY PRESS

+K

Kbd API

Generated from the package prop types and variant definitions.

Kbd

KbdProps

Variants

PropTypeDefault
appearance
amberaquabluecrimsoncyandefaultdestructiveelectricemeraldforestghostglass+36
outline
size
lgmdsm
md

Behavior

PropTypeDefault
keysKeys to render as individual keycaps, e.g. `["⌘", "K"]`. Takes precedence over `children`.ReactNode[] | undefinednone
separatorOptional node rendered between keycaps (e.g. "+" or "then").ReactNodenone

Content

PropTypeDefault
childrenSingle keycap content when `keys` is not provided.ReactNodenone
Inherited HTML props
PropTypeDefault
classNamestring | undefinednone
idstring | undefinednone
onClickMouseEventHandler<HTMLSpanElement> | undefinednone
styleCSSProperties | undefinednone
titlestring | undefinednone

KbdVariant

KbdVariantProps

Behavior

PropTypeDefault
appearance'default' | 'outline' | 'ghost' | 'blue' | 'cyan' | 'green' | 'lime' | 'mint' | 'ocean' | 'sapphire' | 'lavender' | 'ruby' | 'red' | 'slate' | 'zinc' | 'stone' | 'royal' | 'electric' | 'forest' | 'sunset' | 'magenta' | 'crimson' | 'aqua' | 'plum' | 'sky' | 'rose' | 'purple' | 'pink' | 'orange' | 'yellow' | 'teal' | 'indigo' | 'emerald' | 'gradient-blue' | 'gradient-green' | 'gradient-red' | 'gradient-yellow' | 'gradient-purple' | 'gradient-teal' | 'gradient-indigo' | 'gradient-pink' | 'gradient-orange' | 'gray' | 'violet' | 'glass' | 'secondary' | 'destructive' | 'amber' | null | undefinednone
size'md' | 'sm' | 'lg' | null | undefinednone

KbdAnimated

KbdAnimatedProps

animated

Behavior

PropTypeDefault
animationKbdAnimation | undefinednone
appearance'default' | 'outline' | 'ghost' | 'blue' | 'cyan' | 'green' | 'lime' | 'mint' | 'ocean' | 'sapphire' | 'lavender' | 'ruby' | 'red' | 'slate' | 'zinc' | 'stone' | 'royal' | 'electric' | 'forest' | 'sunset' | 'magenta' | 'crimson' | 'aqua' | 'plum' | 'sky' | 'rose' | 'purple' | 'pink' | 'orange' | 'yellow' | 'teal' | 'indigo' | 'emerald' | 'gradient-blue' | 'gradient-green' | 'gradient-red' | 'gradient-yellow' | 'gradient-purple' | 'gradient-teal' | 'gradient-indigo' | 'gradient-pink' | 'gradient-orange' | 'gray' | 'violet' | 'glass' | 'secondary' | 'destructive' | 'amber' | null | undefinednone
keysKeys to render as individual keycaps, e.g. `["⌘", "K"]`. Takes precedence over `children`.ReactNode[] | undefinednone
separatorOptional node rendered between keycaps (e.g. "+" or "then").ReactNodenone
size'md' | 'sm' | 'lg' | null | undefinednone

Content

PropTypeDefault
childrenSingle keycap content when `keys` is not provided.ReactNodenone
Inherited HTML props
PropTypeDefault
classNamestring | undefinednone
idstring | undefinednone
onClickMouseEventHandler<HTMLSpanElement> | undefinednone
styleCSSProperties | undefinednone
titlestring | undefinednone
CSS variable overrides

Kbd CSS variables

Override these kbd variables on :root, a theme selector, or a component wrapper. Structural variables drive the radius and keycap shadow; each appearance sets the keycap background, foreground, and border tokens.

303 variables

Pattern: --zui-<component>-<slot?>-<variant?>-<property>-<state?>-dark?

:root {
  --zui-kbd-radius: 0.375rem;
  --zui-kbd-default-bg: #0f172a;
  --zui-kbd-default-fg: #f8fafc;
  --zui-kbd-default-shadow: 0 1px 2px #0f172a14;
  --zui-kbd-secondary-bg: #e2e8f0;
  --zui-kbd-secondary-fg: #0f172a;
  --zui-kbd-destructive-bg: #f43f5e;
  --zui-kbd-destructive-fg: #ffffff;
  --zui-kbd-outline-border: #0000001a;
  --zui-kbd-outline-bg: #0000000d;
  --zui-kbd-outline-fg: #0f172a;
  --zui-kbd-ghost-fg: #334155;
  --zui-kbd-glass-border: #00000026;
  --zui-kbd-glass-bg: #0000001a;
  --zui-kbd-glass-fg: #0f172a;
  --zui-kbd-emerald-bg: #10b981;
  --zui-kbd-emerald-fg: #ffffff;
  --zui-kbd-indigo-bg: #3730a3;
  --zui-kbd-indigo-fg: #ffffff;
  --zui-kbd-purple-bg: #6b21a8;
  --zui-kbd-purple-fg: #ffffff;
  --zui-kbd-pink-bg: #9d174d;
  --zui-kbd-pink-fg: #ffffff;
  --zui-kbd-rose-bg: #9f1239;
  --zui-kbd-rose-fg: #ffffff;
  --zui-kbd-sky-bg: #0ea5e9;
  --zui-kbd-sky-fg: #ffffff;
  --zui-kbd-teal-bg: #14b8a6;
  --zui-kbd-teal-fg: #ffffff;
  --zui-kbd-yellow-bg: #eab308;
  --zui-kbd-yellow-fg: #ffffff;
  --zui-kbd-orange-bg: #f97316;
  --zui-kbd-orange-fg: #ffffff;
  --zui-kbd-gray-bg: #6b7280;
  --zui-kbd-gray-fg: #ffffff;
  --zui-kbd-amber-bg: #f59e0b;
  --zui-kbd-amber-fg: #ffffff;
  --zui-kbd-violet-bg: #5b21b6;
  --zui-kbd-violet-fg: #ffffff;
  --zui-kbd-gradient-blue-from: #1e40af;
  --zui-kbd-gradient-blue-to: #6b21a8;
  --zui-kbd-gradient-blue-fg: #ffffff;
  --zui-kbd-gradient-green-from: #166534;
  --zui-kbd-gradient-green-to: #3f6212;
  --zui-kbd-gradient-green-fg: #ffffff;
  --zui-kbd-gradient-red-from: #991b1b;
  --zui-kbd-gradient-red-to: #9d174d;
  --zui-kbd-gradient-red-fg: #ffffff;
  --zui-kbd-gradient-yellow-from: #854d0e;
  --zui-kbd-gradient-yellow-to: #9a3412;
  --zui-kbd-gradient-yellow-fg: #ffffff;
  --zui-kbd-gradient-purple-from: #6b21a8;
  --zui-kbd-gradient-purple-to: #9d174d;
  --zui-kbd-gradient-purple-fg: #ffffff;
  --zui-kbd-gradient-teal-from: #115e59;
  --zui-kbd-gradient-teal-to: #155e75;
  --zui-kbd-gradient-teal-fg: #ffffff;
  --zui-kbd-gradient-indigo-from: #3730a3;
  --zui-kbd-gradient-indigo-to: #6b21a8;
  --zui-kbd-gradient-indigo-fg: #ffffff;
  --zui-kbd-gradient-pink-from: #9d174d;
  --zui-kbd-gradient-pink-to: #9f1239;
  --zui-kbd-gradient-pink-fg: #ffffff;
  --zui-kbd-gradient-orange-from: #9a3412;
  --zui-kbd-gradient-orange-to: #991b1b;
  --zui-kbd-gradient-orange-fg: #ffffff;
  --zui-kbd-key-blue-border: #2563eb;
  --zui-kbd-key-blue-bg: #2563eb;
  --zui-kbd-key-blue-fg: #ffffff;
  --zui-kbd-key-blue-bg-hover: #2563eb;
  --zui-kbd-key-cyan-border: #0891b2;
  --zui-kbd-key-cyan-bg: #0891b2;
  --zui-kbd-key-cyan-fg: #083344;
  --zui-kbd-key-cyan-bg-hover: #0891b2;
  --zui-kbd-key-green-border: #16a34a;
  --zui-kbd-key-green-bg: #16a34a;
  --zui-kbd-key-green-fg: #ffffff;
  --zui-kbd-key-green-bg-hover: #16a34a;
  --zui-kbd-key-lime-border: #65a30d;
  --zui-kbd-key-lime-bg: #65a30d;
  --zui-kbd-key-lime-fg: #1a2e05;
  --zui-kbd-key-lime-bg-hover: #65a30d;
  --zui-kbd-key-mint-border: #10b981;
  --zui-kbd-key-mint-bg: #10b981;
  --zui-kbd-key-mint-fg: #064e3b;
  --zui-kbd-key-mint-bg-hover: #10b981;
  --zui-kbd-key-ocean-border: #0284c7;
  --zui-kbd-key-ocean-bg: #0284c7;
  --zui-kbd-key-ocean-fg: #082f49;
  --zui-kbd-key-ocean-bg-hover: #0284c7;
  --zui-kbd-key-sapphire-border: #1d4ed8;
  --zui-kbd-key-sapphire-bg: #1d4ed8;
  --zui-kbd-key-sapphire-fg: #ffffff;
  --zui-kbd-key-sapphire-bg-hover: #1d4ed8;
  --zui-kbd-key-lavender-border: #8b5cf6;
  --zui-kbd-key-lavender-bg: #8b5cf6;
  --zui-kbd-key-lavender-fg: #ffffff;
  --zui-kbd-key-lavender-bg-hover: #8b5cf6;
  --zui-kbd-key-ruby-border: #be123c;
  --zui-kbd-key-ruby-bg: #be123c;
  --zui-kbd-key-ruby-fg: #ffffff;
  --zui-kbd-key-ruby-bg-hover: #be123c;
  --zui-kbd-key-red-border: #dc2626;
  --zui-kbd-key-red-bg: #dc2626;
  --zui-kbd-key-red-fg: #ffffff;
  --zui-kbd-key-red-bg-hover: #dc2626;
  --zui-kbd-key-slate-border: #475569;
  --zui-kbd-key-slate-bg: #475569;
  --zui-kbd-key-slate-fg: #ffffff;
  --zui-kbd-key-slate-bg-hover: #475569;
  --zui-kbd-key-zinc-border: #52525b;
  --zui-kbd-key-zinc-bg: #52525b;
  --zui-kbd-key-zinc-fg: #ffffff;
  --zui-kbd-key-zinc-bg-hover: #52525b;
  --zui-kbd-key-stone-border: #57534e;
  --zui-kbd-key-stone-bg: #57534e;
  --zui-kbd-key-stone-fg: #ffffff;
  --zui-kbd-key-stone-bg-hover: #57534e;
  --zui-kbd-key-royal-border: #4338ca;
  --zui-kbd-key-royal-bg: #4338ca;
  --zui-kbd-key-royal-fg: #ffffff;
  --zui-kbd-key-royal-bg-hover: #4338ca;
  --zui-kbd-key-electric-border: #0ea5e9;
  --zui-kbd-key-electric-bg: #0ea5e9;
  --zui-kbd-key-electric-fg: #ffffff;
  --zui-kbd-key-electric-bg-hover: #0ea5e9;
  --zui-kbd-key-forest-border: #166534;
  --zui-kbd-key-forest-bg: #166534;
  --zui-kbd-key-forest-fg: #ffffff;
  --zui-kbd-key-forest-bg-hover: #166534;
  --zui-kbd-key-sunset-border: #ea580c;
  --zui-kbd-key-sunset-bg: #ea580c;
  --zui-kbd-key-sunset-fg: #ffffff;
  --zui-kbd-key-sunset-bg-hover: #ea580c;
  --zui-kbd-key-magenta-border: #c026d3;
  --zui-kbd-key-magenta-bg: #c026d3;
  --zui-kbd-key-magenta-fg: #ffffff;
  --zui-kbd-key-magenta-bg-hover: #c026d3;
  --zui-kbd-key-crimson-border: #b91c1c;
  --zui-kbd-key-crimson-bg: #b91c1c;
  --zui-kbd-key-crimson-fg: #ffffff;
  --zui-kbd-key-crimson-bg-hover: #b91c1c;
  --zui-kbd-key-aqua-border: #0f766e;
  --zui-kbd-key-aqua-bg: #0f766e;
  --zui-kbd-key-aqua-fg: #ffffff;
  --zui-kbd-key-aqua-bg-hover: #0f766e;
  --zui-kbd-key-plum-border: #7e22ce;
  --zui-kbd-key-plum-bg: #7e22ce;
  --zui-kbd-key-plum-fg: #ffffff;
  --zui-kbd-key-plum-bg-hover: #7e22ce;
  --zui-kbd-shadow: inset 0 -1px 0 #0000001f;
  --zui-kbd-separator-fg: #94a3b8;
}

/* Dark theme variables follow the same names with -dark appended. */
.dark {
  --zui-kbd-default-bg-dark: #f8fafc;
  --zui-kbd-default-fg-dark: #020617;
}

What it does

Kbd turns a key or chord into styled keycaps backed by semantic <kbd> elements. A single key comes from children, while the keys array renders a sequence of keycaps joined by an optional separator node.

The static entry renders instantly, while the animated entry adds a subtle press or pop motion when a keycap mounts.

Composition and API

Import Kbd from the kbd entrypoint, or KbdAnimated from kbd/animated for the motion variant. Use children for a single keycap, keys for a chord, and separator for the node between keycaps. Tune the look with appearance and size.

Common use cases

Reach for Kbd wherever a keyboard shortcut needs to be visible: command palettes, help menus, tooltips and buttons that expose hotkeys, onboarding tours, and settings or cheat-sheet screens that list key bindings.

Accessibility

Each keycap renders a native <kbd> element so the shortcut is exposed as keyboard input to assistive technology. Keep separators meaningful (for example "+" or "then") and ensure the surrounding context names what the shortcut does.

Next.js integration notes

The static Kbd is a plain presentational component and works in server and client components alike. KbdAnimated relies on framer-motion, so render it inside client components or interactive islands.

FAQ

How do I render a multi-key chord?

Pass the keys prop an array such as keys={['⌘', 'K']} and set separator to the node you want between keycaps, like "+" or "then". Each entry renders as its own keycap.

What is the difference between children and the keys prop?

Use children for a single keycap, e.g. <Kbd>Esc</Kbd>. Use keys for a chord of multiple keycaps. When keys is provided it takes precedence over children.

Does Kbd render semantic markup?

Yes. Each keycap is a real <kbd> element wrapped in a span, so assistive technology and styling hooks recognize the shortcut as keyboard input.