Keyboard key
A keycap chip for the native <kbd> element —
shortcut hints in captions, help dialogs, empty states. Em-sized, so
it follows the text it sits in; case is preserved
(j is not J).
Not for an on-screen control's label — <kbd>
means a key the user presses on their keyboard. Referring to a button in
the UI is just its name in text, and if you want it to look like the
control, that is a button.
Inline — a hint in running text
Press / to filter, or Shift + Enter to approve without opening.
View code
<p>Press <kbd class="bo-kbd">/</kbd> to filter, or
<kbd class="bo-kbd">Shift</kbd> + <kbd class="bo-kbd">Enter</kbd> to
approve without opening.</p> The weighted bottom edge is what makes it
read as a key. Combos are separate chips joined by a plain
+ — one chip per physical key.
A shortcut list — composed with Key-value facts
- /
- Focus the filter
- Enter
- Open the selected row
- Shift + Enter
- Approve without opening
- Esc
- Back to the cell
View code
<dl class="bo-kv bo-kv--rows">
<div><dt><kbd class="bo-kbd">/</kbd></dt><dd>Focus the filter</dd></div>
<div><dt><kbd class="bo-kbd">Enter</kbd></dt><dd>Open the selected row</dd></div>
<div><dt><kbd class="bo-kbd">Shift</kbd> + <kbd class="bo-kbd">Enter</kbd></dt><dd>Approve without opening</dd></div>
<div><dt><kbd class="bo-kbd">Esc</kbd></dt><dd>Back to the cell</dd></div>
</dl> .bo-kv --rows aligns keys and descriptions; the chip resets the label uppercase so Esc stays Esc. The full overlay version is the Keyboard map.
Markup
<!-- Always on the native <kbd> element — the semantics come free;
the class only paints the keycap. Combos are separate chips joined
by plain "+" text. -->
<kbd class="bo-kbd">Shift</kbd> + <kbd class="bo-kbd">Enter</kbd> Quick reference generated
| Class | Role |
|---|---|
| .bo-kbd | block (root) |
API generated from CSS
| Blocks | bo-kbd |
|---|---|
| JS required | None — CSS-only. |
- Use the native
<kbd>element, not a span — screen readers and reader modes already know what it means; the class only paints. - One chip per physical key; join combos with plain text (
+,then) so AT reads the sequence naturally. - Case is meaningful and preserved — the chip resets any inherited
text-transform(a grid label context uppercases otherwise). - Forced colors: the border is the boundary and borders survive — no special-casing needed.
- Show the keys your app actually binds — the framework documents its own behavior keys on JS behaviors (generated from the same source the behaviors use).
Contrast — 12 AA pairs this component uses (generated, CI-gated)
| Text | on | Light | Dark |
|---|---|---|---|
| text-secondary | bg-surface | 10.31 | 11.46 |
| text-secondary | bg-muted | 9.37 | 9.75 |
| text-muted | bg-muted | 6.87 | 5.66 |
| text-secondary | bg-selected | 9.88 | 8.41 |
| text-secondary | bg-canvas | 9.86 | 12.82 |
| border-control | bg-muted | 4.39 | 5.66 |
| accent | bg-muted | 4.97 | 7.72 |
| warning-strong | bg-muted | 4.56 | 6.69 |
| danger | bg-muted | 4.39 | 5.19 |
| text-primary | bg-muted | 16.12 | 13.75 |
| success-text | bg-muted | 4.56 | 10.23 |
| danger-text | bg-muted | 5.88 | 7.57 |
Maturity generated
- Introduced
- v0.3.0
- CSS floor
- Chrome/Edge 99 · Firefox 97 · Safari 15.4
- Alignment scored
- 2026-08-21
- Assistive-tech evidence
- None recorded
Pin this component's first release with npm i @busy-office/ui@0.3.0.
The floor is derived from this component's stylesheet alone — set by
@layer — so it sits at or below the
whole framework's Chrome/Edge 119 · Firefox 129 · Safari 17.5.
No assistive-technology runtime result is recorded for any component: it needs a human listening to VoiceOver and NVDA on owner hardware; no gate in this repo can simulate announcement behaviour.
What automation covers instead is test:axe across every page at 1440 and 390, and check:forced-colors — see
accessibility.
Design-system alignment generated
100% (15/15) — how closely this component follows the design language. Each rule is scored 0-3 against a checkable citation; rules that don't apply leave the denominator. Scored 2026-08-21.
| Rule | Score | Evidence |
|---|---|---|
| Typography | 3 / 3 | inline mono now consumes --bo-font-size-mono-inline, the one ratio in the scale — a fraction of the host, which no absolute step can express (94.13) |
| Colour | 3 / 3 | zero raw colour; border/background/text all tokens |
| Spacing | 3 / 3 | min-inline-size, padding and the weighted bottom edge all carry their reason — the edge comment names what it buys ("reads as a KEYCAP") |
| Interaction | n/a | paints the native <kbd>; ships no behavior |
| Content | 3 / 3 | the opener carries the required wrong-choice clause and links the alternative (94.10) |
| Fit | 3 / 3 | shortcut hints in captions, help dialogs and empty states; one chip per physical key |