Button
Buttons are outline by default. Use primary only for the main action on a page.
Variants
Without data-variant a button is outline. Use one
primary button per page.
<div class="stack" data-direction="row" data-gap="sm">
<button type="button" class="btn">Cancel</button>
<button type="button" class="btn" data-variant="primary">Save</button>
<button type="button" class="btn" data-variant="ghost">Skip</button>
<button type="button" class="btn" data-variant="danger">Delete</button>
</div>
Sizes
Icon-only buttons use data-size="icon" or
icon-sm and need an aria-label.
<div class="stack" data-direction="row" data-gap="sm">
<button type="button" class="btn" data-size="sm">Small</button>
<button type="button" class="btn">Default</button>
<button type="button" class="btn" data-size="lg">Large</button>
<button type="button" class="btn" data-size="icon" aria-label="Settings"><i class="icon icon-settings" aria-hidden="true"></i></button>
<button type="button" class="btn" data-size="icon-sm" aria-label="Add"><i class="icon icon-plus" aria-hidden="true"></i></button>
</div>
Icon and disabled
Put the icon before the text. Disabled links use
aria-disabled="true"
<div class="stack" data-direction="row" data-gap="sm">
<a class="btn" href="#"><i class="icon icon-external-link" aria-hidden="true"></i>Open store</a>
<button type="button" class="btn" disabled>Export</button>
<a class="btn" aria-disabled="true">View receipt</a>
</div>
Delete icon button
A red trash icon in an outline frame, or ghost (data-variant="ghost danger") for table rows.
<div class="stack" data-direction="row" data-gap="sm">
<button type="button" class="btn" data-variant="danger" data-size="icon-sm" aria-label="Delete"><i class="icon icon-trash-2" aria-hidden="true"></i></button>
<button type="button" class="btn" data-variant="danger" data-size="icon" aria-label="Delete"><i class="icon icon-trash-2" aria-hidden="true"></i></button>
<button type="button" class="btn" data-variant="ghost danger" data-size="icon-sm" aria-label="Delete"><i class="icon icon-trash-2" aria-hidden="true"></i></button>
</div>
Delete at the end of a row of fields
The button does not shrink in a narrow row (flex-shrink: 0), so it always keeps its size at the end of the row.
<div class="stack" data-gap="sm">
<div class="stack" data-direction="row" data-gap="sm">
<div class="field" style="width: min(10rem, 35%)">
<select aria-label="Metafield">
<option value="">--------</option>
<option value="agent">Agent</option>
<option value="funnel">Funnel</option>
</select>
</div>
<div class="field" style="width: min(16rem, 45%)">
<input type="text" aria-label="Value" value="Downtown store" />
</div>
<button type="button" class="btn" data-variant="danger" data-size="icon" aria-label="Delete field"><i class="icon icon-trash-2" aria-hidden="true"></i></button>
</div>
<div class="stack" data-direction="row" data-gap="sm">
<div class="field" style="width: min(10rem, 35%)">
<select aria-label="Metafield">
<option value="">--------</option>
<option value="agent">Agent</option>
<option value="funnel" selected>Funnel</option>
</select>
</div>
<div class="field" style="width: min(16rem, 45%)">
<input type="text" aria-label="Value" value="flash-sale-11" />
</div>
<button type="button" class="btn" data-variant="danger" data-size="icon" aria-label="Delete field"><i class="icon icon-trash-2" aria-hidden="true"></i></button>
</div>
</div>
Button group
.btn-group joins buttons into one set. Add
role="group" and an aria-label.
<div class="btn-group" role="group" aria-label="Order actions">
<button type="button" class="btn">Archive</button>
<button type="button" class="btn">Report</button>
<button type="button" class="btn">Print</button>
</div>
Pressed toggle buttons
aria-pressed="true" gives a button a grey background
to show it is on. Put data-pressed="single" on the
group to allow one button at a time, or multiple to
let each button toggle on its own (needs JS).
<div class="stack" data-direction="row" data-gap="sm">
<div class="btn-group" role="group" aria-label="Preview width" data-pressed="single">
<button type="button" class="btn" data-size="icon" aria-pressed="true" aria-label="Desktop"><i class="icon icon-monitor" aria-hidden="true"></i></button>
<button type="button" class="btn" data-size="icon" aria-pressed="false" aria-label="Tablet"><i class="icon icon-tablet" aria-hidden="true"></i></button>
<button type="button" class="btn" data-size="icon" aria-pressed="false" aria-label="Mobile"><i class="icon icon-smartphone" aria-hidden="true"></i></button>
</div>
<div class="btn-group" role="group" aria-label="Product filters" data-pressed="multiple">
<button type="button" class="btn" aria-pressed="true">Ready to ship</button>
<button type="button" class="btn" aria-pressed="false">On sale</button>
<button type="button" class="btn" aria-pressed="false">New</button>
</div>
</div>
Button group with a menu
The last button in the group opens a
dropdown with popovertarget.
The popover can sit inside the group without affecting the
buttons' rounded corners.
<div class="stack" data-direction="row" data-gap="sm">
<button type="button" class="btn" data-size="icon" aria-label="Go back"><i class="icon icon-arrow-left" aria-hidden="true"></i></button>
<div class="btn-group" role="group" aria-label="Manage">
<button type="button" class="btn">Archive</button>
<button type="button" class="btn">Report</button>
</div>
<div class="btn-group" role="group" aria-label="Snooze">
<button type="button" class="btn">Snooze</button>
<button type="button" class="btn" data-size="icon" popovertarget="btn-more" aria-label="More options"><i class="icon icon-ellipsis" aria-hidden="true"></i></button>
<div class="dropdown" id="btn-more" popover>
<button type="button" popovertarget="btn-more" popovertargetaction="hide"><i class="icon icon-mail-check" aria-hidden="true"></i>Mark as read</button>
<button type="button" popovertarget="btn-more" popovertargetaction="hide"><i class="icon icon-archive" aria-hidden="true"></i>Archive</button>
<hr />
<button type="button" popovertarget="btn-more" popovertargetaction="hide"><i class="icon icon-clock" aria-hidden="true"></i>Snooze</button>
<button type="button" popovertarget="btn-more" popovertargetaction="hide"><i class="icon icon-calendar" aria-hidden="true"></i>Add to calendar</button>
<button type="button" popovertarget="btn-more" popovertargetaction="hide"><i class="icon icon-list-filter-plus" aria-hidden="true"></i>Add to list</button>
<hr />
<button type="button" data-variant="danger" popovertarget="btn-more" popovertargetaction="hide"><i class="icon icon-trash-2" aria-hidden="true"></i>Trash</button>
</div>
</div>
</div>
Attributes
| Attribute / element | Values | Description |
|---|---|---|
.btn |
button, a |
A button. Use on
<button type="button"> or a link.
|
data-variant |
(none = outline, default), primary,
secondary, ghost,
danger,
ghost danger
|
Button style. Takes several values separated by spaces,
e.g. ghost danger is a red ghost button.
|
data-size |
(none = 36px, default), sm (28px),
lg (40px), xl (48px),
icon, icon-sm
|
icon / icon-sm are 36px / 28px
square buttons for a single icon.
|
aria-label |
text | Required on icon-only buttons. |
.icon |
i, Lucide icon name |
Icon inside a button. Always add
aria-hidden="true".
|
aria-pressed |
true, false |
Toggle button. true shows a grey background.
|
disabled |
boolean | Disables the button. |
aria-disabled |
true |
Disables an a.btn link. |
.btn-group |
div |
Joined group of buttons. Children are .btn.
Add role="group" and an
aria-label.
|
data-pressed |
single, multiple |
Put on .btn-group (or any element) so JS
toggles aria-pressed on the buttons inside:
one at a time, or each on its own.
|
.dropdown |
popover, id |
The group's menu. It can sit inside
.btn-group and opens from a group button with
popovertarget. It does not count as a button
for the rounded corners.
|
API
No functions. Buttons in a [data-pressed] group work
through event delegation, so buttons added later work too.
| Event | Detail | Description |
|---|---|---|
tsunami:pressedchange |
{ button, pressed } |
Fires from the element with
data-pressed (bubbles) after a button click.
button is the clicked button,
pressed is its new state.
|