Kbd

Keyboard key indicator with platform-aware modifier expansion via the shortcut prop. Install Kbd from the VLLNT UI registry with the shadcn CLI.

Report a bug

Keyboard key indicator with platform-aware modifier expansion via the shortcut prop. Part of the core family in VLLNT UI, it ships as a machine-readable registry entry — copy the source directly into your app with the shadcn CLI and own it, no runtime dependency on a component library.

Preview

Switch between light and dark to inspect the embedded Storybook preview.

Installation

Add Kbd to your project with the shadcn CLI. The source lands in your codebase, ready to adapt:

pnpm dlx shadcn@latest add https://ui.vllnt.ai/r/kbd.json

Source

"use client"; import { type ComponentPropsWithoutRef, type ReactNode, useSyncExternalStore, } from "react"; import { cva, type VariantProps } from "class-variance-authority"; import { cn } from "../../lib/utils"; const kbdVariants = cva( "inline-flex select-none items-center justify-center rounded border border-border bg-muted font-mono font-medium text-foreground shadow-[0_1px_0_0_oklch(var(--border))] [&>svg]:h-3 [&>svg]:w-3", { defaultVariants: { size: "md", }, variants: { size: { lg: "h-7 min-w-[1.75rem] px-2 text-sm", md: "h-5 min-w-[1.25rem] px-1.5 text-xs", sm: "h-4 min-w-[1rem] px-1 text-[10px]", }, }, }, ); const MAC_PLATFORM_PATTERN = /mac|iphone|ipad|ipod/i; const MODIFIER_LABELS: Record< "alt" | "ctrl" | "meta" | "mod" | "shift", { mac: string; other: string } > = { alt: { mac: "⌥", other: "Alt" }, ctrl: { mac: "⌃", other: "Ctrl" }, meta: { mac: "⌘", other: "Win" }, mod: { mac: "⌘", other: "Ctrl" }, shift: { mac: "⇧", other: "Shift" }, }; const SPECIAL_KEY_LABELS: Record<string, string> = { arrowdown: "↓", arrowleft: "←", arrowright: "→", arrowup: "↑", backspace: "⌫", delete: "⌦", enter: "↵", escape: "Esc", return: "↵", space: "Space", tab: "⇥", }; const SHORTCUT_SEPARATOR = /\s*\+\s*/; function isMacPlatform(): boolean { if (typeof navigator === "undefined") return false; return MAC_PLATFORM_PATTERN.test(navigator.userAgent); } function noopUnsubscribe(): void { return; } function subscribeNoop(): () => void { return noopUnsubscribe; } function getServerSnapshot(): boolean { return false; } function useIsMac(): boolean { return useSyncExternalStore(subscribeNoop, isMacPlatform, getServerSnapshot); } function isModifier(value: string): value is keyof typeof MODIFIER_LABELS { return Object.hasOwn(MODIFIER_LABELS, value); } function formatToken(token: string, mac: boolean): string { const lowered = token.toLowerCase(); if (isModifier(lowered)) { const labels = MODIFIER_LABELS[lowered]; return mac ? labels.mac : labels.other; } const special = SPECIAL_KEY_LABELS[lowered]; if (special !== undefined) return special; return token.length === 1 ? token.toUpperCase() : token; } /** * Props for {@link Kbd}. * * @public */ export type KbdProps = { /** Optional explicit children. Takes precedence over `shortcut`. */ children?: ReactNode; /** * Shortcut string in the form `"mod+k"` or `"ctrl+shift+p"`. The `mod` * token expands to `⌘` on Mac and `Ctrl` elsewhere. */ shortcut?: string; } & ComponentPropsWithoutRef<"kbd"> & VariantProps<typeof kbdVariants>; /** * Keyboard key indicator. Renders a single key when used with `children`, * or expands a shortcut string with platform-aware modifiers when given a * `shortcut` prop. * * @example * ```tsx * <Kbd>Ctrl</Kbd> + <Kbd>K</Kbd> * * {/* Renders ⌘+K on Mac, Ctrl+K elsewhere *\/} * <Kbd shortcut="mod+k" /> * ``` * * @public */ export const Kbd = ({ children, className, ref, shortcut, size, ...rest }: KbdProps & { ref?: React.Ref<HTMLElement> }) => { const isMac = useIsMac(); if (children !== undefined) { return ( <kbd className={cn(kbdVariants({ size }), className)} ref={ref} {...rest}> {children} </kbd> ); } if (shortcut) { const tokens = shortcut.split(SHORTCUT_SEPARATOR).filter(Boolean); const ariaLabel = tokens .map((token) => formatToken(token, isMac)) .join(" + "); return ( <span aria-label={ariaLabel} className="inline-flex items-center gap-1" role="img" > {tokens.map((token, index) => ( <kbd className={cn(kbdVariants({ size }), className)} key={`${token}-${index.toString()}`} ref={index === 0 ? ref : undefined} {...(index === 0 ? rest : {})} > {formatToken(token, isMac)} </kbd> ))} </span> ); } return ( <kbd className={cn(kbdVariants({ size }), className)} ref={ref} {...rest} /> ); }; Kbd.displayName = "Kbd"; export { kbdVariants };

Stories

Explore every variant and state in the interactive Storybook:

Preview

Switch between light and dark to inspect the embedded Storybook preview.

Dependencies

  • @vllnt/ui@^0.3.0
  • class-variance-authority