Skip to content

COMPONENT

Button

One button, four modifiers, and a disabled state. The base class carries everything they share; a modifier changes only what differs. You will not find a btn-enabled here, and you never will.

Every variant

Primary is the one warm surface on the page: one per view, never two. The last two are both unpressable and they are not saying the same thing β€” disabled means you may not do this, btn-soon means this is coming.

START A PROJECT
HTML
<a href="#" class="btn btn-primary">START A PROJECT</a>
<button type="button" class="btn">SECONDARY</button>
<button type="button" class="btn btn-quiet">QUIET</button>
<button type="button" class="btn btn-sm">SMALL</button>
<button type="button" class="btn" disabled>DISABLED</button>
<button type="button" class="btn btn-soon" aria-disabled="true">INSTALLER, SOON</button>

On the cream slab

Where the ground is warm the roles flip, and the dark button becomes the primary one.

HTML
<a href="#" class="btn btn-on-cream">BOOK AN INTRO CALL</a>

Reference

Read from components/button.css when this page was built, so it cannot fall behind the stylesheet.

CLASSES.btn.btn-primary.btn-quiet.btn-sm.btn-on-cream.btn-soon
SETTINGSSet the first on one element; a theme sets the second for all of them.--btn-shadow β€” falls back to --ds-shadow-control
READS--ds-accent--ds-accent-deep--ds-action--ds-cream--ds-focus-ring--ds-focus-width--ds-font-display--ds-gap--ds-gap-loose--ds-ground--ds-hairline--ds-ink--ds-ink-faint--ds-ink-on-action--ds-ink-on-cream--ds-ink-soft--ds-motion-fast--ds-pad-button--ds-pad-button-sm--ds-radius-control--ds-raised--ds-rule--ds-rule-strong--ds-shadow-flat--ds-shadow-raised--ds-sunk--ds-text-button--ds-track-button

Notes

SOON IS NOT DISABLED

Two controls nobody can press, saying two different things. Disabled means "you may not do this", and a reader who meets a dimmed solid button goes looking for what they did wrong. btn-soon means "this is coming", and a dashed outline reads as an empty slot, which is the truth.

It is the only control here drawn with a different LINE rather than a quieter colour, and that is the whole point: dimming is already what disabled means, so a second dim would be a second spelling of the wrong word.

It still carries aria-disabled, because it is still a control nobody can press and this library renders those inert rather than removing them β€” dropping one re-lays out the row and slides a neighbour under a cursor already on its way down. That is also why the rule names the attribute: the generic disabled rule is more specific and would otherwise repaint it, dim and solid, as the thing it is not.

THE PRIMARY FILL IS --ds-action, AND IT USED TO BE THE CREAM SURFACE

Cream is deliberately the same value in both themes β€” cream is cream. What is not the same is what a cream plate means: against near-black it is a lit panel, and against paper it is barely a tint. So the one door on a light page had no door in it, and the identical markup measured this way round:

ON INK12.75:1 against the ground - unchanged
ON PAPER, BEFORE1.12:1 - a fill nobody could see
ON PAPER, NOW12.16:1 - ink filled, paper label

Nothing could catch it. The CSS is valid, both values were tokens, the box was the right size, and the label is over 10:1 against its own fill either way β€” so a contrast check passes while the button is invisible. It was found by building a second consumer that ships light-first.

--ds-action is the fill of the primary control and --ds-ink-on-action is its label. A theme decides what a call to action is made of: cream on ink, ink on paper. Do not reach past them to a surface again β€” that is the same rule as every other colour decision here, and this is what breaking it looks like.

DISABLED IS AN ATTRIBUTE, NOT A CLASS

Use disabled on a button, or aria-disabled="true" on a link. A class can say a button is disabled while the button stays perfectly clickable β€” it looks inert and behaves live, which is the worst of both. Styling the attribute means the look cannot disagree with the behaviour.

TAB TO ONE

The focus ring is a soft wash of the accent plus a border that moves to it. Both are derived from --ds-accent, so a retheme moves the ring too.