Troupe tokens

Button

A native <button> with a closed set of variants and sizes. No JavaScript. Switch the brand: nothing in the component changes, only the semantic tokens behind it.

Variant × size

Defaults: data-variant="primary", data-size="md". Both also apply when the attribute is missing.

primary
secondary
ghost

States

Hover, active and focus-visible come from :hover, :active and :focus-visible; disabled from the native disabled attribute; loading from aria-busy="true". Loading keeps focus, disabled cannot take it.

Variantdefaulthoverfocus-visibledisabledloading
primary
secondary
ghost
Point at itTab to itdisabledaria-busy="true"

Loading keeps focus

Activate the button with Enter or Space. It switches to aria-busy="true" and keeps focus; the click handler ignores activations while busy. The result is announced in a live region, not by the button.

Reduced motion

Colour changes between states use motion.duration.state-change and stay under reduced motion: they are feedback, not movement. The loading arc turns once per motion.duration.emphasis; with prefers-reduced-motion: reduce it stands still and the busy state stays visible (ADR 0003).

Usage

<link rel="stylesheet" href="@iahola/troupe-tokens/troupe.css">
<link rel="stylesheet" href="@iahola/troupe-components/button/styles.css">

<button type="button" class="troupe-button">Save</button>
<button type="button" class="troupe-button" data-variant="secondary" data-size="sm">Cancel</button>
<button type="button" class="troupe-button" aria-busy="true">Save</button>

Full specification: packages/components/button/README.md.