Design rules
Beaket UI is an Ink & Instrument design system — a printed page you can press. These rules explain why things look the way they do — and what to preserve when you customize.
No decoration
No gradients. No border-radius (except Radio). No blur shadows. No opacity for styling. If it's a border, show the border. If it's a shadow, make it structural.
Accent is state, not decoration
Accent is scarce. It marks what is happening now; it is not a permanent synonym for “interactive.” At rest, pressables rely on neutral material — an ink fill, border, label, or geometry — and carry no standing accent edge. Raised surfaces keep a quiet grey offset shadow.
State precedence
The highest-priority state wins within a visual channel:
| Priority | State | Visual channel |
|---|---|---|
| 1 | Keyboard focus | 2px outer outline on pressables; cap-off edge on writing fields. Invalid focus uses danger instead of accent. |
| 2 | Open ownership / active engagement | Grown offset edge on an overlay owner; 2px inset leading rule on the active menu row. |
| 3 | Hover intent | Thin offset edge on edged pressables, or a neutral tint/text change where an edge would be too dense. |
| 4 | Current selection | Faint lens fill and neutral rim, or ink fill plus position/indicator. Selection never borrows the focus outline. |
| 5 | Persistent affordance | Neutral border, ink surface, label, and geometry only. |
| 6 | Content navigation | Accent text and hover underline for links; muted-to-ink text for breadcrumb ancestors. |
Only spatially distinct channels may stack. An outer keyboard-focus outline may surround an open-owner offset edge or a selected fill. Competing marks in one channel do not stack: open replaces the hover edge, press drops the edge while the control translates, invalid focus replaces the accent focus color, and selection never adds a focus outline. Disabled controls remove interaction edges and focus treatment.
Dense state composition
This server-rendered specimen pins the same outer outline used by focus-visible around an open owner. Its grown offset edge remains visible, while navigation, tabs, the checkbox, and pagination keep their own selection fills or indicators. The cues coexist because they occupy different channels.
Component families
Pressables
Edged buttons and interactive cards are neutral at idle. Hover reveals the thin shadow-offset-action edge; an open overlay owner holds the grown shadow-offset-action-hover edge. Press drops the edge and translates the control by 1px. Ghost and link buttons use tint or underline instead of an edge. Disabled controls use a dashed muted boundary and disabled surface/text, with no edge or focus treatment.
Writing fields and invalid state
Input and Textarea stay quiet at rest. Focus caps the field with a static action edge instead of an outer outline. Invalid focus replaces that accent edge with danger; it does not layer both colors. Read-only focus keeps the neutral surface shade. The caret uses accent and text selection uses the accent tint.
Native choices and lens controls
Checkbox, Switch, and Radio keep a neutral chassis. Hover may reveal a thin edge, while checked state uses ink fill plus a check, thumb position, or dot — never an accent focus look. Pagination holds the current key down with ink fill. Navigation and Tabs are fused lens controls: the current cell gets a faint accent lens and neutral rim, while the strip itself has no standing edge.
Menus and selects
A Select trigger is field-surfaced and quiet at idle and hover. While open it holds the grown edge; keyboard focus may still use the spatially separate outer outline. Menu and Select rows mark keyboard navigation with an accent tint and 2px inset leading rule. An open submenu holds that cue, destructive rows replace it with danger, and disabled rows cannot receive it.
Links and breadcrumbs
Ordinary links use accent text and reveal an underline on hover. Breadcrumb is a trail, not a switcher: ancestors stay muted and darken on hover, the current page uses full ink, and only keyboard focus introduces accent.
One pattern, everywhere
Semantic variant names
Prefer danger for a destructive action or error state in Button, Badge and Alert. Existing names remain supported aliases with identical styling. Alert keeps its GitHub callout vocabulary, icons and default titles; use a custom title when the application needs different wording.
| Component | Canonical role | Existing alias |
|---|---|---|
| Button | danger | destructive |
| Badge | danger | error |
| Alert | danger | caution |
| Alert | info | note |
| Alert | success | tip |
| Alert | accent | important |
warning is already shared, as are success on Button and Badge and info on Badge. Aliases do not introduce new color styles: not every component exposes all six token roles, and Button's neutral primary is not an accent fill.
Pressables share outline-2 outline-border-focus outline-offset-2 for keyboard focus; writing fields use the cap-off edge. Disabled controls share border-dashed border-border-muted bg-bg-disabled text-fg-disabled. Preserve the channel and precedence when composing or customizing components.
Own it, keep it right
You own the code after installation. Every component accepts className — customize freely. But preserve touch targets (44px+), keyboard navigation, and ARIA attributes. The invisible quality matters most.