# Kbd (/ui/components/react/kbd)



<Playground component="kbd" />

## Usage [#usage]

```tsx
import { Kbd, KbdGroup } from '@appica/ui-react/kbd'
```

```tsx
<Kbd>Esc</Kbd>

<KbdGroup>
  <Kbd>⌘</Kbd>
  <Kbd>K</Kbd>
</KbdGroup>
```

`Kbd` renders a single keyboard key — a styled `<kbd>` element — for documenting shortcuts inline, in tooltips, and in menus. Two parts live under `@appica/ui-react/kbd`:

* **`Kbd`** — one key. Three `size`s; the content is whatever you pass as children (a letter, a word like `Esc`, or a glyph like `⌘`).
* **`KbdGroup`** — a wrapper that lays out a sequence of keys with even spacing and propagates a shared `size` to the `Kbd`s inside it.

It's purely presentational: it carries no shortcut behavior, so wire up the actual key handling yourself.

## Examples [#examples]

### Default [#default]

A single key sized to its content — narrow for one letter, wider for a word. The minimum width keeps single characters square.

```tsx
import { Kbd } from '@appica/ui-react/kbd'

export default function KbdDefault() {
  return (
    <div className="flex flex-wrap items-center justify-center gap-2">
      <Kbd>Esc</Kbd>
      <Kbd>Tab</Kbd>
      <Kbd>⌘</Kbd>
      <Kbd>⇧</Kbd>
      <Kbd>↵</Kbd>
      <Kbd>Space</Kbd>
    </div>
  )
}
```

### Sizes [#sizes]

Three sizes — `sm`, `md` (default), and `lg` — scale the height, padding, and text together so a key sits comfortably next to surrounding type.

```tsx
import { Kbd } from '@appica/ui-react/kbd'

const sizes = ['sm', 'md', 'lg'] as const

export default function KbdSizes() {
  return (
    <div className="flex flex-wrap items-center justify-center gap-4">
      {sizes.map((size) => (
        <Kbd key={size} size={size}>
          ⌘ K
        </Kbd>
      ))}
    </div>
  )
}
```

### Key combinations [#key-combinations]

Wrap several `Kbd`s in a `KbdGroup` to show a chord. The group spaces the keys evenly and pushes a shared `size` down to each one — and leaves any non-`Kbd` child (like a `+` separator) untouched.

```tsx
import { Kbd, KbdGroup } from '@appica/ui-react/kbd'

export default function KbdGroupExample() {
  return (
    <div className="flex flex-col items-center gap-4 text-sm">
      <KbdGroup>
        <Kbd>⌘</Kbd>
        <Kbd>⇧</Kbd>
        <Kbd>P</Kbd>
      </KbdGroup>

      <KbdGroup>
        <Kbd>Ctrl</Kbd>
        <span className="text-foreground-muted">+</span>
        <Kbd>Alt</Kbd>
        <span className="text-foreground-muted">+</span>
        <Kbd>Del</Kbd>
      </KbdGroup>

      <span className="text-foreground-muted">
        Press{' '}
        <KbdGroup size="sm">
          <Kbd>⌘</Kbd>
          <Kbd>K</Kbd>
        </KbdGroup>{' '}
        to open the command menu
      </span>
    </div>
  )
}
```

### Shortcut list [#shortcut-list]

A common layout: action on one side, its shortcut on the other. The `KbdGroup` keeps each combo aligned and consistently sized.

```tsx
import { Kbd, KbdGroup } from '@appica/ui-react/kbd'

const shortcuts = [
  { action: 'Open command menu', keys: ['⌘', 'K'] },
  { action: 'New file', keys: ['⌘', 'N'] },
  { action: 'Search', keys: ['⌘', 'F'] },
  { action: 'Toggle sidebar', keys: ['⌘', 'B'] },
]

export default function KbdShortcuts() {
  return (
    <ul className="flex w-full max-w-80 flex-col gap-0.5">
      {shortcuts.map(({ action, keys }) => (
        <li
          key={action}
          className="bg-background-subtle flex items-center justify-between gap-4 px-4 py-2.5 text-sm first:rounded-t-lg last:rounded-b-lg"
        >
          <span>{action}</span>
          <KbdGroup size="sm">
            {keys.map((key) => (
              <Kbd key={key}>{key}</Kbd>
            ))}
          </KbdGroup>
        </li>
      ))}
    </ul>
  )
}
```

### Inside a button [#inside-a-button]

Drop a `Kbd` into a [`Button`](/ui/components/react/button) as a trailing shortcut hint — a familiar pattern for search and command-menu triggers.

```tsx
import { Button } from '@appica/ui-react/button'
import { Kbd } from '@appica/ui-react/kbd'
import { Search } from '@appica/icons-react'

export default function KbdInButton() {
  return (
    <Button variant="outline" className="gap-3">
      <Search data-icon="start" />
      Search
      <Kbd size="sm" data-icon="end" className="-me-0.5">
        ⌘ K
      </Kbd>
    </Button>
  )
}
```

### Inside a tooltip [#inside-a-tooltip]

`Kbd` detects a [`Tooltip`](/ui/components/react/tooltip) surface and inverts its colors automatically, so a shortcut stays legible against the dark tooltip background with no extra styling.

```tsx
import { Tooltip, TooltipProvider, TooltipTrigger, TooltipContent } from '@appica/ui-react/tooltip'
import { Button } from '@appica/ui-react/button'
import { Kbd } from '@appica/ui-react/kbd'
import { Bookmark } from '@appica/icons-react'

export default function KbdInTooltip() {
  return (
    <TooltipProvider>
      <Tooltip>
        <TooltipTrigger
          render={
            <Button variant="outline" size="icon-md" aria-label="Save">
              <Bookmark />
            </Button>
          }
        />
        <TooltipContent className="flex items-center gap-2">
          Save
          <Kbd size="sm">⌘ S</Kbd>
        </TooltipContent>
      </Tooltip>
    </TooltipProvider>
  )
}
```

## RTL [#rtl]

Every Appica UI component supports right-to-left layouts out of the box. Set the `dir` attribute on a container (commonly your `<html>` element) so CSS logical properties resolve correctly, and wrap your tree in `DirectionProvider` so direction-aware behavior follows the same direction.

```tsx
import { DirectionProvider } from '@appica/ui-react/providers/direction-provider'

export default function RootLayout({ children }) {
  return (
    <html lang="ar" dir="rtl">
      <body>
        <DirectionProvider dir="rtl">{children}</DirectionProvider>
      </body>
    </html>
  )
}
```

The list and its labels flip to the right, while each shortcut's keys stay in left-to-right reading order — pin the `KbdGroup` with `dir="ltr"` so a `⌘ K` combo isn't reversed into `K ⌘`. For setup details and caveats, see the [RTL guide](/ui/docs/react/rtl).

<RtlPreview component="kbd" />

## API reference [#api-reference]

`Kbd` and `KbdGroup` are styled native elements (`<kbd>` and `<span>`) — they're not Base UI primitives. Each forwards `ref` and every remaining attribute to its underlying element.

### Kbd [#kbd]

A single key. Renders a `<kbd>`.

| Prop        | <ColMinWidth width="200">Type</ColMinWidth> | Default | <ColMinWidth width="240">Description</ColMinWidth>            |
| ----------- | ------------------------------------------- | ------- | ------------------------------------------------------------- |
| `size`      | <Code>'sm' \| 'md' \| 'lg'</Code>           | `'md'`  | Height, padding, and text scale. Inherited from a `KbdGroup`. |
| `children`  | `ReactNode`                                 | —       | The key label — a letter, word, or glyph.                     |
| `className` | `string`                                    | —       | Extra classes, merged via `tailwind-merge`.                   |

### KbdGroup [#kbdgroup]

A row of keys. Renders a `<span>` and forwards `size` to its `Kbd` children.

| Prop        | <ColMinWidth width="200">Type</ColMinWidth> | Default | <ColMinWidth width="240">Description</ColMinWidth>                   |
| ----------- | ------------------------------------------- | ------- | -------------------------------------------------------------------- |
| `size`      | <Code>'sm' \| 'md' \| 'lg'</Code>           | `'md'`  | Default size applied to each child `Kbd` that doesn't set its own.   |
| `children`  | `ReactNode`                                 | —       | The keys (and any separators). A `Kbd` with its own `size` keeps it. |
| `className` | `string`                                    | —       | Extra classes, merged via `tailwind-merge`.                          |

## Accessibility [#accessibility]

* `Kbd` renders the semantic `<kbd>` element, which assistive tech recognizes as keyboard input.
* The component is decorative documentation, not an interactive control — pair it with the real key handler, and make sure the shortcut also has a discoverable, non-keyboard way to trigger the same action.
* When a glyph alone might be ambiguous (e.g. `⌘` vs "Command"), consider an `aria-label` on the `Kbd` so it's announced clearly.
* Inside a `KbdGroup`, keys read in source order; pin the group to `dir="ltr"` under RTL so a combo isn't announced or displayed in reverse.
