Kbd
A styled keyboard key indicator for displaying shortcuts and key combinations.
ui/kbd.tsx
import {
ArrowCornerDownLeftIcon,
ArrowDownIcon,
ArrowLeftXIcon,
ArrowUpIcon,
ArrowWall2RightIcon,
CmdIcon,
ControlIcon,
OptIcon,
ShiftIcon,
} from "blode-icons-react";
import { cva } from "class-variance-authority";
import type { VariantProps } from "class-variance-authority";
import type * as React from "react";
import { cn } from "@/lib/utils";
type KbdIcon =
| "mod"
| "shift"
| "enter"
| "command"
| "ctrl"
| "alt"
| "tab"
| "backspace"
| "up"
| "down";
const kbdVariants = cva(
"pointer-events-none inline-flex h-5 w-fit min-w-5 select-none items-center justify-center gap-1 rounded-sm px-1.5 font-medium font-sans text-xs ring-1 ring-inset [&_svg:not([class*='size-'])]:size-3",
{
defaultVariants: {
variant: "default",
},
variants: {
variant: {
default:
"bg-muted text-muted-foreground ring-border [[data-slot=tooltip-content]_&]:bg-background/20 [[data-slot=tooltip-content]_&]:text-background [[data-slot=tooltip-content]_&]:ring-background/20 dark:[[data-slot=tooltip-content]_&]:bg-background/10 dark:[[data-slot=tooltip-content]_&]:ring-background/10",
tooltip:
"bg-background/20 text-background ring-background/20 dark:bg-background/10 dark:ring-background/10",
},
},
},
);
interface KbdProps extends React.ComponentProps<"kbd">, VariantProps<typeof kbdVariants> {
icon?: KbdIcon;
}
const iconMap: Record<KbdIcon, React.ReactNode> = {
alt: <OptIcon className="size-3" />,
backspace: <ArrowLeftXIcon className="size-3" />,
command: <CmdIcon className="size-3" />,
ctrl: <ControlIcon className="size-3" />,
down: <ArrowDownIcon className="size-3" />,
enter: <ArrowCornerDownLeftIcon className="size-3" />,
mod: <CmdIcon className="size-3" />,
shift: <ShiftIcon className="size-3" />,
tab: <ArrowWall2RightIcon className="size-3" />,
up: <ArrowUpIcon className="size-3" />,
};
const Kbd = ({ className, variant, children, icon, ...props }: KbdProps) => {
const content = icon ? iconMap[icon] : children;
return (
<kbd className={cn(kbdVariants({ variant }), className)} data-slot="kbd" {...props}>
{content}
</kbd>
);
};
const KbdGroup = ({ className, ...props }: React.ComponentProps<"kbd">) => (
<kbd
className={cn("inline-flex items-center gap-1", className)}
data-slot="kbd-group"
{...props}
/>
);
export { Kbd, KbdGroup };
- Where it goes
- kanban