Build websites 10x faster with HextaUI Blocks — Learn more
UI/UI

Kbd

A keyboard key component for displaying keyboard shortcuts and key combinations.

CtrlShiftAltEnterEscSpaceTab
<div className="flex flex-wrap gap-4 items-center">
  <Kbd>Ctrl</Kbd>
  <Kbd>⌘</Kbd>
  <Kbd>Shift</Kbd>
  <Kbd>Alt</Kbd>
  <Kbd>Enter</Kbd>
  <Kbd>Esc</Kbd>
  <Kbd>Space</Kbd>
  <Kbd>Tab</Kbd>
</div>

Installation

Install following dependencies:

npm install pnpm add class-variance-authority
pnpm add pnpm add class-variance-authority
yarn add pnpm add class-variance-authority
bun add pnpm add class-variance-authority

Copy and paste the following code into your project.

components/ui/kbd.tsx
"use client";

import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";

const kbdVariants = cva(
  "inline-flex items-center justify-center font-mono text-xs font-medium bg-[hsl(var(--hu-muted))] text-[hsl(var(--hu-muted-foreground))] border border-[hsl(var(--hu-border))] rounded-md border-b-3 transition-all duration-75 cursor-pointer select-none active:translate-y-[1px] active:border-b-[1px]  hover:bg-[hsl(var(--hu-muted))]/80",
  {
    variants: {
      variant: {
        default:
          "bg-[hsl(var(--hu-muted))] text-[hsl(var(--hu-muted-foreground))] border-[hsl(var(--hu-border))]",
        outline:
          "bg-transparent border-[hsl(var(--hu-border))] text-[hsl(var(--hu-foreground))] hover:bg-[hsl(var(--hu-accent))]",
        solid:
          "bg-[hsl(var(--hu-foreground))] text-[hsl(var(--hu-background))] border-[hsl(var(--hu-foreground))] hover:bg-[hsl(var(--hu-foreground))]/90",
        secondary:
          "bg-[hsl(var(--hu-secondary))] text-[hsl(var(--hu-secondary-foreground))] border-[hsl(var(--hu-border))] hover:bg-[hsl(var(--hu-secondary))]/80",
      },
      size: {
        xs: "h-5 px-1.5 text-[10px] min-w-[1.25rem]",
        sm: "h-6 px-2 text-xs min-w-[1.5rem]",
        md: "h-7 px-2.5 text-sm min-w-[1.75rem]",
        lg: "h-8 px-3 text-sm min-w-[2rem]",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "sm",
    },
  },
);

export interface KbdProps
  extends React.HTMLAttributes<HTMLElement>,
    VariantProps<typeof kbdVariants> {
  keys?: string[];
  onClick?: () => void;
}

const Kbd = React.forwardRef<HTMLElement, KbdProps>(
  ({ className, variant, size, keys, children, onClick, ...props }, ref) => {
    // If keys array is provided, render multiple kbd elements
    if (keys && keys.length > 0) {
      return (
        <span
          className="inline-flex items-center gap-1"
          ref={ref as React.Ref<HTMLSpanElement>}
          onClick={onClick}
        >
          {keys.map((key, index) => (
            <React.Fragment key={index}>
              <kbd
                className={cn(kbdVariants({ variant, size }), className)}
                {...props}
              >
                {key}
              </kbd>
              {index < keys.length - 1 && (
                <span className="text-[hsl(var(--hu-muted-foreground))] text-xs px-1">
                  +
                </span>
              )}
            </React.Fragment>
          ))}
        </span>
      );
    }

    // Single kbd element
    return (
      <kbd
        className={cn(kbdVariants({ variant, size }), className)}
        ref={ref}
        onClick={onClick}
        {...props}
      >
        {children}
      </kbd>
    );
  },
);

Kbd.displayName = "Kbd";

export { Kbd, kbdVariants };
npx hextaui@latest add kbd
pnpm dlx hextaui@latest add kbd
yarn dlx hextaui@latest add kbd
bun x hextaui@latest add kbd

Usage

import { Kbd } from "@/components/ui/Kbd";
Press <Kbd>Ctrl</Kbd> + <Kbd>S</Kbd> to save

Examples

Default

PressEnterto submit
<div className="flex flex-wrap gap-2 items-center">
  <span>Press</span>
  <Kbd>Enter</Kbd>
  <span>to submit</span>
</div>

Sizes

CtrlCtrlCtrlCtrl
<div className="flex flex-wrap gap-4 items-center">
  <Kbd size="xs">Ctrl</Kbd>
  <Kbd size="sm">Ctrl</Kbd>
  <Kbd size="md">Ctrl</Kbd>
  <Kbd size="lg">Ctrl</Kbd>
</div>

Variants

DefaultOutlineSolidSecondary
<div className="flex flex-wrap gap-4 items-center">
  <Kbd variant="default">Default</Kbd>
  <Kbd variant="outline">Outline</Kbd>
  <Kbd variant="solid">Solid</Kbd>
  <Kbd variant="secondary">Secondary</Kbd>
</div>

Key Combinations

Save:Ctrl+S
Copy:+C
Select All:Ctrl+Shift+A
Force Quit:++Esc
<div className="flex flex-col gap-4">
  <div className="flex items-center gap-2">
    <span>Save:</span>
    <Kbd keys={["Ctrl", "S"]} />
  </div>
  <div className="flex items-center gap-2">
    <span>Copy:</span>
    <Kbd keys={["⌘", "C"]} />
  </div>
  <div className="flex items-center gap-2">
    <span>Select All:</span>
    <Kbd keys={["Ctrl", "Shift", "A"]} />
  </div>
  <div className="flex items-center gap-2">
    <span>Force Quit:</span>
    <Kbd keys={["⌘", "⌥", "Esc"]} />
  </div>
</div>

Common Shortcuts

UndoCtrl+Z
RedoCtrl+Y
FindCtrl+F
ReplaceCtrl+H
New TabCtrl+T
Close TabCtrl+W
RefreshF5
Dev ToolsF12
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm">
  <div className="flex justify-between items-center">
    <span>Undo</span>
    <Kbd keys={["Ctrl", "Z"]} />
  </div>
  <div className="flex justify-between items-center">
    <span>Redo</span>
    <Kbd keys={["Ctrl", "Y"]} />
  </div>
  <div className="flex justify-between items-center">
    <span>Find</span>
    <Kbd keys={["Ctrl", "F"]} />
  </div>
  <div className="flex justify-between items-center">
    <span>Replace</span>
    <Kbd keys={["Ctrl", "H"]} />
  </div>
  <div className="flex justify-between items-center">
    <span>New Tab</span>
    <Kbd keys={["Ctrl", "T"]} />
  </div>
  <div className="flex justify-between items-center">
    <span>Close Tab</span>
    <Kbd keys={["Ctrl", "W"]} />
  </div>
  <div className="flex justify-between items-center">
    <span>Refresh</span>
    <Kbd>F5</Kbd>
  </div>
  <div className="flex justify-between items-center">
    <span>Dev Tools</span>
    <Kbd>F12</Kbd>
  </div>
</div>

Function Keys

F1F2F3F4F5F6F7F8F9F10F11F12
<div className="flex flex-wrap gap-2">
  {Array.from({ length: 12 }, (_, i) => (
    <Kbd key={i} size="xs">
      F{i + 1}
    </Kbd>
  ))}
</div>

Arrow Keys

<div className="flex flex-col items-center gap-2">
  <Kbd>↑</Kbd>
  <div className="flex gap-2">
    <Kbd>←</Kbd>
    <Kbd>↓</Kbd>
    <Kbd>→</Kbd>
  </div>
</div>

Special Characters

Command:
Option:
Shift:
Control:
Return:
Delete:
<div className="flex flex-wrap gap-4 items-center">
  <div className="flex items-center gap-2">
    <span>Command:</span>
    <Kbd>⌘</Kbd>
  </div>
  <div className="flex items-center gap-2">
    <span>Option:</span>
    <Kbd>⌥</Kbd>
  </div>
  <div className="flex items-center gap-2">
    <span>Shift:</span>
    <Kbd>⇧</Kbd>
  </div>
  <div className="flex items-center gap-2">
    <span>Control:</span>
    <Kbd>⌃</Kbd>
  </div>
  <div className="flex items-center gap-2">
    <span>Return:</span>
    <Kbd>↩</Kbd>
  </div>
  <div className="flex items-center gap-2">
    <span>Delete:</span>
    <Kbd>⌫</Kbd>
  </div>
</div>

Props

PropTypeDefault
children?
React.ReactNode
undefined
className?
string
undefined
keys?
string[]
undefined
size?
"xs" | "sm" | "md" | "lg"
"sm"
variant?
"default" | "outline" | "solid" | "secondary"
"default"
Edit on GitHub

Last updated on