Skip to main content

Button

An action. A <button> does something; an <a href> goes somewhere, styled the same when it's an action-like link ("Open the calculator").

CSS: css/components/button.css. Classes: .al-button, .al-button--danger, .al-button--icon, .al-button--primary, .al-button--quiet, .al-button--sm, .al-button-group, .al-button-group--vertical.

On its own page, in English and Arabic
On its own page, in English and Arabic

Anatomy​

HTML
<button type="button" class="al-button al-button--primary">Save offer</button>
<button type="button" class="al-button">Compare offers</button>
<button type="button" class="al-button al-button--quiet">Add a step</button>
<button type="button" class="al-button al-button--danger">Delete offer</button>
<button type="button" class="al-button al-button--icon" aria-label="Edit offer">
<svg class="al-icon" aria-hidden="true"><use href="dist/icons.svg#al-icon-edit"></use></svg>
</button>

Label, optionally with an icon before it (or a trailing chevron for "Move to…"). Icon-only buttons are square.

Variants and sizes​

KindClassUse
Primary--primaryThe one action the view or dialog is for. One per view
Secondary(none)Other actions, bordered
Quiet--quietSecondary and repeated actions in text: Edit, Add a step, Clear. Replaces hunt's .link-button and .app-add
Danger--dangerDestroys something: secondary or quiet; --danger --primary only as the last step of a confirmation
Icon--iconIcon alone, with aria-label and a tooltip

Sizes: default (40px) and --sm (32px). Quiet buttons keep a 24px minimum target in both.

Button group (.al-button-group, in React ButtonGroup): related actions joined in a row, one border between each and no gap (Day, Week, Month; Undo, Redo), or a column with --vertical. Each is still its own button, with its own name; the group is role="group", named by aria-label ("Period"). Icon buttons in a group have their border. For one choice among options, a segmented control instead.

HTML
<div class="al-button-group" role="group" aria-label="History">
<button class="al-button al-button--sm al-button--icon" aria-label="Undo">…</button>
<button class="al-button al-button--sm al-button--icon" aria-label="Redo">…</button>
</div>

States​

StateHow
HoverSunk background, border to text colour (primary darkens); quiet buttons underline
FocusThe system outline (2px, offset 2px)
ActiveNudged down 1px
Unavailablearia-disabled="true" (stays focusable; the reason is next to it or in aria-describedby); disabled only inside forms where it can't be explained
Busyaria-busy="true": the label stays, a spinner follows it; clicks are ignored, but Enter and Space aren't, so the handler checks aria-busy first and returns

Keyboard​

Enter and Space activate (native). Focus order follows the DOM.

ARIA​

Name from the label; icon buttons need aria-label. Toggle buttons use aria-pressed. Menu buttons: aria-haspopup="menu" and aria-expanded (see menu).

Right to left​

Icons before the label stay before it (on the right in Arabic). Directional icons (arrow, chevron) take .al-mirror.

Do and don't​

Do
  • Name the action and its object: "Save offer", "Archive 3".
  • Put the primary last in a dialog's action row, first in a page's.
  • Explain why something's unavailable, beside it.
Don't
  • "OK", "Submit", "Yes", "Click here".
  • Two primary buttons in one view.
  • Disable a button to mean "busy".
  • Use a danger button for something that can be undone; do it and offer Undo.

Tokens​

The 24 tokens it uses

--al-border-hairline, --al-button-height, --al-button-height-sm, --al-button-padding-inline, --al-button-radius, --al-color-accent, --al-color-accent-hover, --al-color-control, --al-color-danger, --al-color-danger-hover, --al-color-on-accent, --al-color-surface-sunk, --al-color-text, --al-duration-fast, --al-ease-standard, --al-font-sans, --al-size-target-min, --al-size-target-touch, --al-space-1, --al-space-2, --al-space-3, --al-text-base, --al-text-sm, --al-weight-medium