Design System / 07.1
Actions
Buttons and links share squared edges, restrained motion, and a 44px target. This chapter also covers clipboard feedback, skip navigation, keyboard hints, and theme controls.
Button
The house button: squared, uppercase, and hairline-bordered. Hover and active states reduce opacity instead of inverting color, paired with a one-pixel lift and press. Both sizes keep a 44px target floor; reduced motion removes the translation.
Live specimen
Rendered output
API reference
Inputs, types, and behavior
- Inputvariant
- Type"solid" | "ghost" | "light" | "primary"
- BehaviorDefault "solid" is a 15% ink hairline; "ghost" is borderless; "light" supplies a 15% paper hairline and label for dark sections. "primary" is the one filled control in the system — ink on paper, flipping with the theme — reserved for the single action a surface exists to complete. At most one per surface.
- Inputdisabled / aria-disabled
- Typeboolean / "true"
- BehaviorBoth paint with --ink-dim, an opaque mix of ink into paper, rather than opacity — so a disabled control on a tinted ground does not sink below the readable floor. aria-disabled keeps the control in the tab order for a busy submit.
- Inputsize
- Type"md" | "sm"
- BehaviorDefault "md". Both sizes are at least 44px tall; "sm" reduces type, padding, and minimum width.
- Inputhref
- Typestring?
- BehaviorRenders an <a> instead of a <button>; anchor-only and button-only props typecheck per branch.
- Input…rest
- Typenative props
- BehaviorSpread onto the element. type defaults to "button".
Roll button
Two stacked labels in a vertical clip. Hover, or the controlled active state, rolls one label out and its twin in — 300ms in on the entry curve, 250ms out. Hover also dims the complete control.
Live specimen
Rendered output
API reference
Inputs, types, and behavior
- Inputlabel
- Typestring
- BehaviorThe resting label.
- InputsecondLabel
- Typestring?
- BehaviorText of the incoming twin; defaults to label for a self-swap.
- Inputactive
- Typeboolean?
- BehaviorControlled swap for toggle use. Add the matching state attribute; when using aria-pressed with different labels, supply one stable aria-label.
- Inputhref
- Typestring?
- BehaviorRenders an <a> instead of a <button>.
Bracket button
A mono, terminal-style control: static brackets frame a label that rolls through its clip. Same roll mechanism and toggle contract as the roll button.
Live specimen
Rendered output
API reference
Inputs, types, and behavior
- Inputlabel
- Typestring
- BehaviorThe resting label. Brackets are aria-hidden decoration.
- InputsecondLabel
- Typestring?
- BehaviorIncoming twin for toggle use; defaults to label.
- Inputactive
- Typeboolean?
- BehaviorControlled swap; add the matching state attribute and keep a toggle button's accessible name stable.
- Inputhref
- Typestring?
- BehaviorRenders an <a> instead of a <button>.
Dot link
A navigation link with a persistent leading square dot. Hover nudges the row over 300ms while the complete link dims; reduced motion keeps the row settled without animation.
Live specimen
Rendered output
API reference
Inputs, types, and behavior
- Inputhref
- Typestring
- BehaviorAlways an anchor.
- Inputlabel
- Typestring
- BehaviorUppercase micro label rendered next to the dot.
- InputclassName
- Typestring?
- BehaviorMerged onto the <a>.
- Input…rest
- Typeanchor props
- BehaviorSpread onto the <a>.
Tag
An uppercase micro label in mono type. Choose plain text, a hairline box, or bracketed text.
Live specimen
Rendered output
API reference
Inputs, types, and behavior
- Inputvariant
- Type"plain" | "hairline" | "bracket"
- BehaviorDefault "plain". "hairline" draws a 1px border-current box; "bracket" wraps the label in [ ].
- Inputchildren
- TypeReactNode
- BehaviorThe label content.
Skip link
An accessibility control: hidden above the viewport until keyboard focus lands, then instantly visible in primary-button styling. One is mounted just below — focus the demo link to reveal it.
Live specimen
Rendered output
Render it as the first child of the page and give the target region the matching id (default #main). It appears immediately when focused.
API reference
Inputs, types, and behavior
- Inputhref
- Typestring = "#main"
- BehaviorAnchor of the region focus should jump to.
- Inputchildren
- TypeReactNode?
- BehaviorLabel; defaults to "Skip to content".
Slide link
.link-slide-target supplies the 44px link and forwards its self-dimming hover to the inner .link-slide one-line clip.
Underlined link
Read the identity guidance.underlined-link — directional hairline underline and self-dimming hover; use .tap-target for standalone controls.
Copy button
Writes a value to the clipboard and shows a transient confirmation. Three presentations share one behavior: a hairline button, unbordered inline mono text, and an icon-only variant. Every presentation rests at full readable ink, dims on hover/active, and keeps a 44px target. It guards for a missing Clipboard API and clears its timer on unmount and re-click.
Live specimen
Rendered output
Button · inline · icon · disabled
API reference
Inputs, types, and behavior
- Inputvalue
- Typestring
- BehaviorText written to the clipboard on click.
- Inputvariant
- Type"button" | "inline" | "icon"
- BehaviorDefault "button" — hairline chrome; "inline" is unbordered mono text; "icon" is icon-only with a guaranteed tap target.
- Inputlabel / copiedLabel
- Typestring
- BehaviorIdle and confirmation labels — default "Copy" / "Copied". label doubles as the icon variant's aria-label.
- Inputtimeout
- Typenumber
- BehaviorMilliseconds the copied state holds before reverting. Default 1500.
- InputonCopy
- Type() => void
- BehaviorFires after the value is successfully written.
- InputclassName
- Typestring?
- BehaviorMerged onto the button; any other button props pass through.
Alert and StatusDot carry the same monochrome-first approach, with a named tint only where the host defines the token. Those two live in their own families.
Kbd
A single keyboard key cap: a squared, hairline-bordered mono glyph that sits inline with ink text. Single characters get a min-width so ⌘, K and ↵ read as evenly weighted caps.
Live specimen
Rendered output
API reference
Inputs, types, and behavior
- Inputchildren
- TypeReactNode
- BehaviorThe key glyph or label.
- InputclassName
- Typestring?
- BehaviorMerged onto the <kbd> element.
Button group
A segmented strip of Buttons with collapsed 1px borders. The caller marks selection with aria-pressed or a variant change.
Live specimen
Rendered output
API reference
Inputs, types, and behavior
- Inputlabel
- Typestring?
- BehaviorAccessible name for the role="group".
- Inputchildren
- TypeButtons
- BehaviorAnything accepting className works; adjacent left edges are suppressed so translucent borders collapse to one hairline.
- Input…rest
- Typediv props
- BehaviorSpread onto the group wrapper.
Spotlight button
A squared button with a faint ink arc interrupting its hairline. The arc recedes while the complete control dims and moves by one physical pixel. Reduced motion keeps the same resting detail and applies state changes without interpolation.
Live specimen
Rendered output
API reference
Inputs, types, and behavior
- Inputchildren
- TypeReactNode
- BehaviorLabel, rendered squared, uppercase, tracked.
- Inputarc
- Typenumber = 120
- BehaviorRadius of the erased arc in px; smaller is a tighter interruption. The deprecated `glow` alias forwards here through v0.12.x.
- Inputsize
- Type"md" | "sm"
- BehaviorDefault "md"; "sm" reduces type, padding, and minimum width. Both retain a 44px target.
- Inputhref
- Typestring?
- BehaviorRenders an <a> like Button; otherwise a <button type="button">. Native props for either forward through.
- InputclassName
- Typestring?
- BehaviorMerged onto the rendered element.
Theme switch
Inverts the document’s ink and paper tokens by toggling data-theme="dark" on <html> and persisting theme in local storage. Every mounted switch observes the root attribute, so repeated controls keep their pressed state synchronized. This specimen changes the entire catalog theme.
Live specimen
Rendered output
API reference
Inputs, types, and behavior
- InputclassName
- Typestring?
- BehaviorMerged last onto the button. The control supplies its stable accessible name, pressed state, 44px target, and button type.
Pair it with the documented pre-paint boot script and suppressHydrationWarning on the root html element to avoid a theme flash and React hydration warning.