BUTTON SYSTEM: Complete reference for all button variants and states
VARIANTS: Solid | Outline | Link | Sizes | States | Layout

Buttons are the primary way users take actions in your application. Use semantic colors to convey intent (primary for main actions, danger for destructive actions, etc.).

Solid Buttons

Solid Buttons: High-emphasis buttons with colored backgrounds. Use for primary actions and important calls-to-action.

<button class="tw-btn tw-btn-primary">Primary</button>

Outline Buttons Retired

Outline Buttons — RETIRED 2026-08-11. Do not use in new work. Kept here, and in the CSS, only so CDN consumers can identify what they already have. Use the .tw-btn-soft-* tier instead — it is the same medium-emphasis step and every mapping is contrast-checked: outline-primarysoft-primary, and the same for secondary, success, danger, warning and info. bin/ds validate fails on any new outline usage.

<button class="tw-btn tw-btn-outline-primary">Primary</button>

Tertiary Buttons

Tertiary Buttons: Low-emphasis buttons with transparent background. Use for tertiary actions, supplementary options, or when you need minimal visual weight.

<button class="tw-btn tw-btn-tertiary">Tertiary Button</button>

Button Sizes

Sizes: Three size options to match your UI density needs. Default size works for most cases.

<button class="tw-btn tw-btn-primary tw-btn-lg">Large</button>
<button class="tw-btn tw-btn-primary tw-btn-sm">Small</button>

Icon Buttons

Icon Buttons: Buttons with Font Awesome Pro v6 icons. Use icons to reinforce meaning and improve scannability. Icons inherit the button's text size and color automatically.

Icon + Text (Leading Icon)

Text + Icon (Trailing Icon)

Icon-Only Buttons

Icon Button Sizes

Icon + Text with Sizes

Common Icon Patterns

<button class="tw-btn tw-btn-primary"><i class="fa-solid fa-check"></i> Save</button>
<button class="tw-btn tw-btn-primary tw-btn-icon" aria-label="Save"><i class="fa-solid fa-floppy-disk"></i></button>

Disabled State

Disabled Buttons: Use the disabled attribute to indicate buttons that cannot be interacted with. Disabled buttons have reduced opacity and no hover effects.

Disabled Solid Buttons

Disabled Outline Buttons

Disabled Tertiary Button

<button class="tw-btn tw-btn-primary" disabled>Disabled</button>

Loading State

Action in flight: add .tw-btn-loading, swap the label ("Save" → "Saving…"), and set disabled + aria-busy="true". The spinner draws from the button's own text colour, so it works on every variant; the class overrides the disabled dim — a busy button reads active, not unavailable.

Loading vs idle

Sizes

<button class="tw-btn tw-btn-primary tw-btn-loading" disabled aria-busy="true">Saving…</button>

Block Buttons (Full Width)

Block Buttons: Full-width buttons that span their container. Use for mobile interfaces, forms, or when you need a button to take up the entire available width.

<button class="tw-btn tw-btn-primary tw-btn-block">Block button</button>

Heavy Buttons (Bold Text)

Heavy Buttons: Buttons with bold text for extra emphasis. Add .tw-btn-heavy to any button variant when you need the text to stand out more.

Solid Heavy Buttons

Outline Heavy Buttons

Comparison: Normal vs Heavy

<button class="tw-btn tw-btn-primary tw-btn-heavy">Heavy Button</button>

Multiline Buttons (Edge cases)

Multiline Buttons: Buttons with multiple text lines (2 lines optimal) to support extra context in constrained space. Add .tw-btn-multiline to any button variant when you need to display in 2 lines.

Solid Multiline Buttons

Outline Multiline Buttons

Comparison: Normal vs Multiline

Comparison: Multiline in different sizes

<button class="tw-btn tw-btn-primary tw-btn-multiline">Multiline<br>Button</button>

Common Usage Patterns

Real-world examples: Typical button combinations you'll use in forms, dialogs, and interfaces.

Form Actions (Primary + Secondary)

Destructive Action with Confirmation

Call to Action (CTA)

Multiple Actions

Button Groups

Button Groups: Group multiple buttons together with shared borders. Use for related actions or toggles like toolbar buttons or view switchers.

Horizontal Group

Solid Button Groups

Outline Button Groups

Vertical Group

Button Group Sizes

<div class="tw-btn-group"><button class="tw-btn tw-btn-secondary">Left</button>...</div>
<div class="tw-btn-group-vertical">...</div>

Dropdown Buttons

Dropdown Toggle: Buttons with dropdown arrows to indicate a menu or additional options. Add the .tw-dropdown-toggle class to automatically display a dropdown arrow.

Solid Dropdowns

Outline Dropdowns

Dropdown Sizes

<button class="tw-btn tw-btn-primary tw-dropdown-toggle">Dropdown</button>

Split Buttons

One main action + attached alternatives: the label button performs the default action; the caret opens a menu of variants ("Save" | ▾ → Save & add another, Save as draft). A .tw-btn-group whose second slot is a full .tw-dropdown wrapper — the caret carries .tw-dropdown-toggle .tw-dropdown-toggle-split and must have an aria-label. Use a split only when one action clearly dominates; equals get a plain dropdown.

<div class="tw-btn-group"><button class="tw-btn tw-btn-primary">Save</button><div class="tw-dropdown"><button class="tw-btn tw-btn-primary tw-dropdown-toggle tw-dropdown-toggle-split" aria-label="More save options"></button>…</div></div>

Disabled With a Reason

Never leave a user guessing: a disabled button can't explain itself — it takes no hover and no focus. Wrap it in .tw-btn-disabled-wrap with tabindex="0" and put the tooltip (the reason) on the wrapper: pointer events fall through the disabled child, and keyboard users can Tab to the wrapper to hear the reason. The cursor reads not-allowed over the whole button.

<span class="tw-btn-disabled-wrap" tabindex="0" data-controller="tooltip" data-tooltip-content-value="Why it's disabled"><button class="tw-btn tw-btn-primary" disabled>Action</button></span>

Checkbox & Radio Button Groups

Button-style Checkboxes/Radios: Form controls styled as buttons. Use hidden .tw-btn-check inputs with <label> elements styled as buttons for accessible toggle controls.

Checkbox Buttons (Multiple Select)

Radio Buttons (Single Select)

Different Color Variants

<input type="checkbox" class="tw-btn-check" id="check1">
<label class="tw-btn tw-btn-primary" for="check1">Checkbox</label>

Pagination

Pagination: Navigation component for paging through content. Use .tw-pagination container with .tw-page-item and .tw-page-link classes.

Basic Pagination

With Disabled States

Pagination Sizes

Grouped Numbers

<ul class="tw-pagination"><li class="tw-page-item tw-active"><a class="tw-page-link">1</a></li></ul>

Quick Reference

Base: .tw-btn
Solid: .tw-btn-{primary|secondary|success|danger|warning|info}
Outline: .tw-btn-outline-{primary|secondary|success|danger|warning|info}
Tertiary: .tw-btn-tertiary
Sizes: .tw-btn-sm (small) | default (no class) | .tw-btn-lg (large)
Icons: .tw-btn-icon (square icon-only button) | use <i class="fa-*"> for Font Awesome icons
Layout: .tw-btn-block (full width) | .tw-btn-heavy (bold text)
Groups: .tw-btn-group (horizontal) | .tw-btn-group-vertical | .tw-btn-group-{sm|lg}
Dropdown: .tw-dropdown-toggle (adds arrow indicator)
Checkbox/Radio: .tw-btn-check (input) + .tw-btn (label)
Pagination: .tw-pagination > .tw-page-item > .tw-page-link | .tw-page-item.tw-active | .tw-page-item.tw-disabled
Pagination Sizes: .tw-pagination-sm | .tw-pagination-lg
State: disabled attribute (reduces opacity, disables interaction)
Usage: Combine classes like .tw-btn.tw-btn-primary.tw-btn-lg or .tw-btn.tw-btn-outline-danger.tw-btn-sm

Soft tier

Soft: tinted fill, no border weight — quieter than solid, more present than tertiary. Reuses the badge/tag soft tokens, so a soft button and a soft badge of the same variant read as one family. Use for secondary actions in dense surfaces (DR-2026-13).

matching badge
<button class="tw-btn tw-btn-soft-primary">Assign reviewer</button>

Link button

Link: an action that lives inside a sentence. Resets the button box entirely — no padding, border or radius, baseline-aligned, inherits the surrounding text size. Not for control rows: beside a primary button use .tw-btn-tertiary, whose matching height and hit area is the point. And if it navigates, it's a real <a href>, not a button.

Changes are saved automatically as you type.

Used to calculate distance.

12 offers expire on Friday

Families who haven't responded lose their place.

Contrast — the control row, where tertiary is correct:

<p>Changes are saved automatically. <button class="tw-btn tw-btn-link" type="button">Learn how autosave works</button></p>

Dashed (Add-Item)

DASHED: .tw-btn-dashed — transparent ground, dashed neutral border, normal weight

The add-another row at the end of a repeating list — reminders, contacts, custom fields, criteria. The dashed edge says "this is a slot you can fill", which a solid button does not; it is the quietest button in the system on purpose, because it must not out-rank the form's real submit. Pair it with .tw-btn-block so it spans the list it belongs to, and always label it with a leading + or plus icon plus the noun it adds. Do not use it for anything destructive, and do not use it as a general secondary button — that is .tw-btn-secondary.

Open day reminders

Email — 7 days before
SMS — 1 day before

Sizes — inline use

<button class="tw-btn tw-btn-dashed tw-btn-block" type="button"><i class="fa-regular fa-plus" aria-hidden="true"></i> Add another reminder</button>