Buttons and actions

Buttons say what happens

A button is a promise. Its label says exactly what will happen, it looks as important as the action is, and it responds the instant it is pressed.

  • Labels are verbs in sentence case: “Send 3 emails”, “Issue licence”, not “Submit” or “OK”.
  • One primary button per view. Secondary for alternatives, tertiary for low-emphasis actions.
  • Keep the action's name through the flow: “Publish” → “Publishing…” → “Published”.
  • Put the primary action last (right) in a button row; in RTL layouts it moves to the left.

Variants and states

Every variant has the same six states. The loading state keeps the button's width so the layout never jumps.

Variants × states

DefaultHoverFocusPressedDisabledLoading PrimarySecondaryTertiaryDangerDanger (secondary)
VariantUseNever
PrimaryThe single most important actionMore than one per view
SecondaryAlternatives, cancel, backFor the main action
TertiaryLow-emphasis actions, inline actions in cards and tablesFor destructive actions
DangerIrreversible destructive actions, usually inside a confirmation dialogAs the first button a user sees
Danger (secondary)Entry point to a destructive flow (opens the confirmation)For reversible actions
InverseOn Midnight or image backgrounds in marketingIn product UI

Anatomy and tokens

Primary button

Part / stateValueToken
Height32 / 40 / 48px--n-size-control-*
Padding12 / 16 / 22px
Radius8px--n-radius-sm
LabelText Medium 15px (13.5 / 16)--n-font-family-text
BackgroundGulf 70 (light), Oasis 30 (dark)--n-action
HoverGulf 80 / Oasis 20--n-action-hover
TextWhite / Midnight 90--n-text-on-action
Icon18px, 8px gap, leading--n-size-icon-md
Focus3px ring, 2px offset--n-focus

Instant feedback on press

Respond within 100ms

  • On press: 1px down shift (pressed state) immediately.
  • If the result takes longer than ~300ms: switch to the loading state (spinner, label hidden, width kept) and ignore further clicks.
  • On success: change the label to the past tense (“Sent”) with a check for 1.5 seconds, or close the surface; confirm with a toast if the result is not visible.
  • On failure: restore the button and show the error next to it, never only in a toast.

Click to see loading, success and failure.

Icon buttons

Square, labelled for assistive tech

  • 40px square (32px small), 20px icon, 8px radius.
  • Always an aria-label and a tooltip with the same text.
  • Use only for universally understood actions: close, more, search, copy, settings. Otherwise use a text button.
  • Floating icon buttons over images use the translucent Midnight style with backdrop blur.
SearchSettings

Menu (burger) button

Three lines that become a cross

  • Use only where navigation must collapse: below 960px, or in dense product chrome.
  • Placed at the leading edge of the header (left; right in RTL), before the logo.
  • Animates into a close icon in 220ms when the menu opens; aria-expanded and aria-controls are required.
  • The opened menu is a drawer from the same edge, with a scrim; Esc and the scrim close it.
Click it

Copy buttons

Top right of what is copied

  • Sits in the top-right corner of the code block or field it copies (top-left in RTL), inside the frame with 10px inset.
  • Visible on hover and keyboard focus on desktop; always visible on touch.
  • On click: label changes to “Copied” with a check for 1.5s. No toast needed.
  • For single values (IDs, tokens, keys) use an inline icon button after the value.
curl -fsS https://admiral.example.gov/healthz
key_9f2c…41ab

Button groups and split buttons

Group and split button

For mutually exclusive views prefer the segmented control on the Navigation page. Split buttons combine a default action with a menu of alternatives.

  • Inline links are Gulf 70 (Oasis 30 on dark), underlined with a 1px line at 3px offset; 2px on hover.
  • Links go somewhere; buttons do something. Never style a navigation link as a button or vice versa, except CTAs in marketing.
  • External links get the external-link icon and open in the same tab unless the user would lose work.
  • Link text describes the destination: “Read the residency guide”, never “click here”.

Code

<button class="n-btn n-btn--primary" type="button">Save</button>
<button class="n-btn n-btn--secondary n-btn--sm">Cancel</button>
<button class="n-btn n-btn--primary" aria-busy="true">Saving</button>   <!-- loading -->
<button class="n-icon-btn" aria-label="Close">…svg…</button>

<!-- Tailwind -->
<button class="inline-flex items-center gap-2 h-control-md px-4 rounded-sm bg-n-action text-n-on-action
  font-medium hover:bg-n-action-hover active:translate-y-px focus-visible:outline-3
  focus-visible:outline-offset-2 focus-visible:outline-n-focus disabled:opacity-disabled">Save</button>

Dos and don'ts

Do

  • Write specific verb labels.
  • Show loading inside the button and keep its width.
  • Confirm destructive actions in a dialog with the danger button.
  • Give icon buttons labels and tooltips.

Don't

  • Use more than one primary button per view.
  • Disable a button without saying why.
  • Use colour other than the variants (no green “Go” buttons).
  • Use “OK”, “Submit” or “Click here”.

Last updated on 14 October 2026