# Kbd

> A keyboard key or shortcut, drawn as a keycap

Status: beta. Added in Components 2.16.0.

A keyboard key or shortcut, drawn as a keycap.

## Import

```tsx
import { Kbd } from '@oztix/roadie-components/kbd'
```

## Examples

### Default

Pass a key as text. Known key names, in any case, show their glyph or short word: `Enter` shows the return glyph and the word.

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

### Keys

`keys` draws a combination, each key on its own keycap. `mod` is the platform's main modifier: ⌘ on Apple devices and Ctrl elsewhere. `shift`, `alt` and `ctrl` follow the platform too, as glyphs on Apple devices and words elsewhere.

```tsx
<Kbd keys={['mod', 'k']} />
<Kbd keys={['mod', 'shift', 'p']} />
<Kbd keys={['alt', 'arrowup']} />
```

The known names are `enter`, `escape`, `tab`, `space`, `backspace`, `delete`, `arrowup`, `arrowdown`, `arrowleft`, `arrowright`, `mod`, `meta`, `shift`, `alt` and `ctrl`. They also take the aliases `return`, `esc`, `del`, `up`, `down`, `left`, `right`, `cmd` and `command` (for `mod`), `option` and `control`, and `KeyboardEvent.key` values such as `ArrowUp`, `Escape` and `Meta`. `meta` is ⌘ on Apple devices and Win elsewhere. Any other key shows as text, with a single letter in capitals.

### Emphasis

`subtle`, the default, is a soft keycap tinted from the surrounding text colour, with no border, so it suits any surface, a strong button included. `normal` is its own opaque, bordered surface, so it keeps its own colours on any fill. `subtler` is plain text in the surrounding colour, for places that already frame it, such as a menu row. Off Apple devices, `subtler` joins keys with a plus, as in Ctrl+D.

```tsx
{/* Normal */}
<Kbd keys={['mod', 'd']} emphasis='normal' />
{/* Subtle */}
<Kbd keys={['mod', 'd']} />
{/* Subtler */}
<Kbd keys={['mod', 'd']} emphasis='subtler' />
```

### Sizes

`md` suits a toolbar or a field. Use `sm` inside a button or beside small text.

```tsx
<Kbd keys={['mod', 'k']} size='sm' />
<Kbd keys={['mod', 'k']} size='md' />
```

### Composition

Put the hint inside the control it triggers. Kbd is hidden from assistive tech, so the button's name stays "Search", and `aria-keyshortcuts` carries the real shortcut.

```tsx
<Button aria-keyshortcuts='Meta+K Control+K'>
  <MagnifyingGlassIcon weight='bold' className='size-4' />
  Search
  <Kbd keys={['mod', 'k']} size='sm' combined />
</Button>
```

`Menu.Item` and `Tooltip.Content` take a `shortcut` and render it through Kbd: plain `subtler` keys in a menu row, and small keycaps in a tooltip.

```tsx
<Menu>
  <Menu.Trigger render={<Button>Actions</Button>} />
  <Menu.Content>
    <Menu.Item icon={<PencilSimpleIcon weight='bold' />} shortcut={['mod', 'e']} aria-keyshortcuts='Meta+E Control+E'>Edit</Menu.Item>
    <Menu.Item icon={<CopyIcon weight='bold' />} shortcut={['mod', 'd']} aria-keyshortcuts='Meta+D Control+D'>Duplicate</Menu.Item>
  </Menu.Content>
</Menu>
<Tooltip>
  <Tooltip.Trigger render={<IconButton aria-label='Search' aria-keyshortcuts='Meta+K Control+K'><MagnifyingGlassIcon weight='bold' className='size-4' /></IconButton>} />
  <Tooltip.Content shortcut={['mod', 'k']}>
    <Tooltip.Arrow />
    Search
  </Tooltip.Content>
</Tooltip>
```

### Combined

`combined` draws a combination on one keycap, such as ⌘K, for keys pressed together. Off Apple devices, the keys are joined with a plus, as in Ctrl+K.

```tsx
{/* Separate */}
<Kbd keys={['mod', 'shift', 'p']} />
{/* Combined */}
<Kbd keys={['mod', 'shift', 'p']} combined />
```

### Separator

`separator` goes between keys, in separate keycaps or a combined one. Use a word such as `then` for a sequence, keys pressed one after another. By default there is none on Apple devices, and off them a plus inside a combined keycap or between subtler keys.

```tsx
{/* Plus */}
<Kbd keys={['mod', 'k']} separator='+' />
{/* Sequence */}
<Kbd keys={['g', 'i']} separator='then' />
```

### Announced

In instructions, the keys are the content. `announce` reads each key aloud by its name, such as "Command" or "Control", "Enter" and "Up arrow".

```tsx
<p>
  Press <Kbd keys={['mod', 'enter']} size='sm' announce /> to send the message.
</p>
```

## Guidelines

### Hint where people use a keyboard

**Do**

```tsx
<Kbd keys={['mod', 'k']} />
```

Show a hint on keyboard-first surfaces, like search, command menus and the row actions of a busy table. Kbd hides itself on touch screens, which have no keyboard to hint at.

**Don’t**

Don't make a hint the only way to learn an action. A shortcut speeds up an action that is already on screen.

### Name keys, not symbols

**Do**

```tsx
<Kbd keys={['mod', 's']} />
```

Pass `mod` for the main modifier. Each reader sees their own platform's key.

**Don’t**

```tsx
<Kbd>⌘S</Kbd>
```

Don't type a platform's symbols. Windows and Android readers would see keys they don't have.

### Combine keys where space is tight

**Do**

```tsx
<Kbd keys={['mod', 'k']} size='sm' combined />
```

Combine keys inside a button or a field, where one keycap reads as one hint.

**Don’t**

```tsx
<Kbd keys={['mod', 'shift', 'p']} combined announce />
```

Don't combine keys in instructions or a shortcut list. Separate keycaps show each key to press.

### Show a sequence with a word

**Do**

```tsx
<Kbd keys={['g', 'i']} separator='then' />
```

Put `then` between keys pressed one after another, so a sequence doesn't read as a combination.

**Don’t**

```tsx
<Kbd keys={['g', 'i']} combined />
```

Don't combine keys that aren't pressed together. One keycap means one chord.

### Choose the emphasis by place

**Do**

```tsx
<Kbd keys={['mod', 'k']} />
```

Keep `subtle` in toolbars, fields, buttons and tooltips. Use `subtler` in menu rows, and `normal` in a shortcut list or a help page, where keys should stand out.

**Don’t**

```tsx
<Kbd keys={['mod', 'k']} emphasis='normal' />
```

Don't put a `normal` keycap inside a button. Its border competes with the button's own edge.

## Accessibility

- Kbd is `aria-hidden` by default. It repeats a shortcut the control already announces, so put the real shortcut on the control as `aria-keyshortcuts`, such as `aria-keyshortcuts='Meta+K Control+K'`. Bind the keys yourself.
- Use `announce` where the keys are the content, such as instructions in a help article. Each key is then read by name, and a word `separator` such as `then` is read between them. A symbol separator such as `+` stays silent.
- On strong success, warning, danger and brand-secondary fills, a subtle keycap's tint takes its keys as low as about APCA Lc 53, under the Lc 60 those fills' labels reach. In muted text, such as `text-subtle` helper copy, it reads at about Lc 74 in light mode. That's accepted because the keys are a visual hint that repeats the control's `aria-keyshortcuts`. Use `normal` or `subtler` there when the keys must read as strongly as the label.
- Kbd is hidden on screens without hover, so touch readers never see a key they can't press. Announced keys stay, because they are content. To keep every hint inside a container visible, for example a help page about shortcuts or a tablet with a keyboard, set `data-keyboard-hints='always'` on the container.
- `mod`, `meta`, `shift`, `alt` and `ctrl` depend on the platform. The server and the first render show an empty keycap in their place, and the right key appears once the page has loaded, so hydration never mismatches.

## API reference

### Kbd

```tsx
import { Kbd } from '@oztix/roadie-components/kbd'
```

- `keys`: `readonly string[]`. A combination: `['mod', 'k']`. Overrides `children`.
- `combined`: `boolean`. Defaults to `false`. Draws `keys` in one keycap, such as ⌘K, rather than a keycap each. `subtler` keys have no keycap, so it changes nothing there.
- `separator`: `ReactNode`. Placed between `keys`, such as `'+'` or `'then'`. By default nothing on Apple devices, and off them a plus inside a combined keycap or between subtler keys, as in Ctrl+K. Text such as `'then'` is read aloud when `announce` is on; `null` or `false` removes the default.
- `emphasis`: `"normal" | "subtle" | "subtler"`. Defaults to `subtle`. `subtle` is a soft keycap tinted from the surrounding text colour. `normal` is its own bordered surface and keeps its own colours on any fill. `subtler` is plain text in the surrounding colour, for menus.
- `size`: `"sm" | "md"`. Defaults to `md`. The keycap's height. `subtler` has no keycap, so it ignores size.
- `announce`: `boolean`. Defaults to `false`. Read the keys aloud, by name. Off by default: a control carries its shortcut in `aria-keyshortcuts`, so the hint is visual. Turn it on where the keys are the content, such as instructions in prose. Announced keys also stay on touch screens.

Docs updated 10 Oct 2026.
