eo-n/ui
UIComponentsKbd

Kbd

Displays keyboard shortcuts with appropriate styling.

+K

Installation

CLI

npx shadcn@latest add "https://eo-n.vercel.app/r/kbd"

Manual

Install the following dependencies:

npm install @radix-ui/react-slot

Copy and paste the following code into your project.

import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
 
import { cn } from "@/lib/utils";
 
export const kbdVariants = cva(
  "inline-flex items-center justify-center text-center text-xs font-medium tracking-tight shadow-sm gap-1.5 text-muted-foreground",
  {
    variants: {
      variant: {
        default: "bg-accent",
        outline: "bg-background outline outline-border",
        ghost: "bg-transparent shadow-none",
      },
      size: {
        default: "h-6 rounded px-1.5",
        sm: "h-5 rounded-sm px-1",
        lg: "h-7 rounded-md px-2",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
);
 
const KEY_DESCRIPTIONS: Record<string, string> = {
  "⌘": "Command",
  "⇧": "Shift",
  "⌥": "Option",
  "⌃": "Control",
  Ctrl: "Control",
  "⌫": "Backspace",
  "⎋": "Escape",
  "↩": "Return",
  "⇥": "Tab",
  "⌤": "Enter",
  "↑": "Arrow Up",
  "↓": "Arrow Down",
  "←": "Arrow Left",
  "→": "Arrow Right",
  "⇪": "Caps Lock",
  fn: "Function",
  "⌦": "Delete",
  "⇞": "Page Up",
  "⇟": "Page Down",
  "↖": "Home",
  "↘": "End",
  "↕": "Page Up/Down",
  "↔": "Left/Right",
} as const;
 
export type KbdVariants = VariantProps<typeof kbdVariants>;
 
interface KbdProps extends React.ComponentProps<"div">, KbdVariants {
  asChild?: boolean;
}
 
function Kbd({ className, variant, size, asChild, ...props }: KbdProps) {
  const Comp = asChild ? Slot : "div";
 
  return (
    <Comp
      data-slot="kbd"
      className={cn(kbdVariants({ className, size, variant }))}
      {...props}
    />
  );
}
 
interface KbdKeyProps extends React.ComponentProps<"span"> {
  asChild?: boolean;
}
 
function KbdKey({
  className,
  asChild,
  title: titleProp,
  children,
  ...props
}: KbdKeyProps) {
  const Comp = asChild ? Slot : "span";
  const keyText = children?.toString() ?? "";
  const title = titleProp ?? KEY_DESCRIPTIONS[keyText] ?? keyText;
  return (
    <abbr title={title} className="no-underline">
      <Comp data-slot="kbd-key" className={cn(className)} {...props}>
        {children}
      </Comp>
    </abbr>
  );
}
 
interface KbdSeparatorProps extends React.ComponentProps<"span"> {
  asChild?: boolean;
}
 
function KbdSeparator({
  className,
  children = "+",
  asChild,
  ...props
}: KbdSeparatorProps) {
  const Comp = asChild ? Slot : "span";
  return (
    <Comp
      data-slot="kbd-separtor"
      className={cn("text-muted-foreground", className)}
      {...props}
    >
      {children}
    </Comp>
  );
}
 
export { Kbd, KbdKey, KbdSeparator };
Update the import paths to match your project setup.

Usage

Import all parts and piece them together.

import { Kbd, KbdKey, KbdSeparator } from "@/components/ui/kbd";
<Kbd>
  <KbdKey>⇧<KbdKey>
  <KbdSeparator />
  <KbdKey>Enter<KbdKey>
</KbdKey>

Predefined Key Titles

The component provides predefined titles for common keyboard symbols.

<Kbd>
  <KbdKey>↩</KbdKey> {/* Shows "Return" on hover */}
  <KbdKey>⌃</KbdKey> {/* Shows "Control" on hover */}
</Kbd>

Personalized Key Titles

You can define custom titles for any key

<Kbd>
  <KbdKey title="Ctrl">⌃</KbdKey>
  <KbdSeparator />
  <KbdKey title="Shift">⇧</KbdKey>
  <KbdSeparator />
  <KbdKey title="Command Palette">P</KbdKey>
</KbdKey>

Examples

Default

+K

Outline

+

Ghost

++F

API Reference

Root

The primary container for displaying keyboard shortcuts.

PropTypeDefault
variant
"default" | "outline" | "ghost"
"default"
size
"default" | "sm" | "lg"
"default"
asChild
boolean
false
Data AttributeValue
[data-slot]"kbd"

Key

Represents an individual keyboard key.

PropTypeDefault
title
string
-
asChild
boolean
false
Data AttributeValue
[data-slot]"kbd-key"

Separtor

A visual separator between multiple keys.

PropTypeDefault
asChild
boolean
false
Data AttributeValue
[data-slot]"kbd-separtor"

On this page