Button

Starts an action, like sending a message or saving a change.

Examples

Busy while sending

Ready

Confirm or go back

A link to more

With an icon

Styles

  • primarydefault

  • solid

  • secondary

  • outline

  • ghost

  • destructive

  • link

Sizes

  • sm

  • mddefault

  • lg

  • icon-sm

  • icon

  • icon-lg

Pending

  • falsedefault

  • true

States

  • rest

  • hover

  • focus

  • active

  • disabled

Usage

When to use it
Use
The person does something with their money or account: send, pay, save, add a card.
Use
The view has one main action that has to be found in a second.
Use
A row or toolbar repeats a small action on every item (ghost, icon sizes).
Not for
The control moves to another page. Use a link; variant="link" is for actions that stay on the page.
Not for
The control turns a setting on or off at once. Use Switch.
Not for
The person chooses one of two to five views. Use Segmented.
Not for
It is a topic or filter the person toggles. Use Chip.

Rules

12 rules
Must
Use variant="primary" once per view; make every other action solid, secondary, outline or ghost. Because two lime buttons leave the person guessing which one moves the money.
Must
Set pending and keep the children; never swap the label while an action runs. Because a new label changes the width and the accessible name mid-press.
Must
Set type="submit" on the Button that submits a form; Base UI defaults to type="button". Because without it the Button presses and Enter in a field never submit the form.
Must
Use destructive only on the confirming button inside a dialog; keep the trigger outline or ghost. Because red on the trigger alarms before anything is at stake and takes the weight from the real confirm.
Must
Give icon-sm, icon and icon-lg an aria-label. Because the glyph is aria-hidden, so a screen reader announces only "button".
Never
Put white text on the lime fill; use variant="primary", which carries near-black text. Because white on the lime fails contrast in both themes.
Never
Add glow classes to other buttons; the glow marks primary and destructive only. Because the glow marks the next step, and a glowing Share competes with Send for it.
Must
Pass only placement classes in className, never fills, heights or radii. Because a hand-set fill skips the variant's hover, pressed and forced-colors states and its checked contrast.
Should
Say why a button is disabled in text beside it; a disabled button takes no focus or hover on touch.
Should
Label with a verb and its object in sentence case.
Should
Show a money amount in an Amount beside the button, not in the label.
Should
Use size="lg" (48px) for the main action on phone-first surfaces.

Accessibility

5 checks
Focus shows a 2px olive outline on :focus-visible, on every variant.
Name icon sizes with aria-label; the glyph is aria-hidden.
Pending sets aria-busy and keeps the idle name.
Report results in a role="status" region, never in the label.
Text on the lime and on the red passes 4.5:1 at every glow stop, in both themes; Color lists each ratio, computed from tokens.css.

Edge cases

11 edge cases
Long label
Never wraps and never grows past its container: a text label too long for the column ends in an ellipsis, and the full label stays the accessible name.
Row narrower than its buttons
Buttons are shrink-0 and overflow. Use flex-wrap.
Right to left
The row mirrors. An arrow icon does not flip; use rtl:-scale-x-100.
Zoom 200%
The label grows sideways and the fixed height stays; nothing clips.
Slow action
Pass pending even when false so the box is as wide as the pending layer from the start.
Double click or held Enter
Pending blocks repeats until the parent clears it.
Empty or unnamed icon button
Announced as "button"; Lime has no development warning.
Inside a form
Submits only with type="submit".
Inside an anchor
Two tab stops; render the Button as the link with render.
Forced colors
The glow drops and every variant but link gets a 1px ButtonText border.
Reduced motion
No press scale; the lit layer switches without a fade; the spinner keeps turning.

API

7 props
variant
'primary' | 'solid' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'link' default 'primary'
size
'sm' | 'md' | 'lg' | 'icon-sm' | 'icon' | 'icon-lg' default 'md'
pending
boolean
icon
ReactNode
disabled
boolean default false
render
ReactElement
className
string

Tokens

26 tokens
--accent
#e4f222
--on-accent
#0f0f0d
--glow-accent-from
#dbec1c
--glow-accent-to
#f6ff7c
--glow-accent-edge
rgb(255 255 255 / 0.7)
--glow-accent-bloom
rgb(255 255 255 / 0.28)
--glow-accent-cast
112 120 20
--ink
#0f0f0d
--ink-hover
#2a2a26
--fg-inverse
#ffffff
--surface-2
#efeeea
--surface-3
#e6e4df
--line-strong
#cfcdc6
--danger
#d93636
--on-danger
#ffffff
--fg-disabled
#a6a49b
--control-sm
32px
--control-md
40px
--control-lg
48px
--radius-control
999px
--ring
var(--accent-line)
--focus-offset
2px
--dur-instant
80ms
--dur-base
200ms
--ease-out
cubic-bezier(0.16, 1, 0.3, 1)
--dur-spin
900ms

Install

For your coding agent

GitHub

Please star me pookie

141

A new design system every week

Leave your email before you copy the prompt.