Button
A raised control that lifts on hover and sinks when pressed.
On this page
A button is a small raised sheet with a half-pixel contour. It lifts by half a pixel under the pointer and sinks into a well when pressed, so its state reads through light and depth rather than color. Use .btn on a <button> for actions and on an <a> for navigation that should look like one.
Button
<button type="button" class="btn">Cancel</button><button type="button" class="btn btn-primary">Save changes</button>#Variants
The default button is moonstone. Choose the variant by the weight of the action:
btn-primaryis ink on moonstone and pearl on obsidian. Use one per view, for the action the view exists for.btn-quiethas no material until touched; use it in toolbars, headers and dense rows.btn-dangerkeeps the raised material and gives its label the danger ink.btn-brandis the one hued control, in the brand indigo: a moment such as a homepage call to action or an upgrade. Use at most one per view. Its face, edge and glow are mixed from--color-brand, so it follows your brand color.
Variants
<button type="button" class="btn">Default</button><button type="button" class="btn btn-primary">Primary</button><button type="button" class="btn btn-quiet">Quiet</button><button type="button" class="btn btn-danger">Delete</button><button type="button" class="btn btn-brand">Get started</button>#Destructive actions
btn-danger alone is the quiet form: a raised button whose label is in the danger ink, for a delete among other actions. Together with btn-primary it becomes the confirming button of a destructive act, filled with the danger color the way a brand button is filled with the brand. Keep the filled form for the last step, such as the button that confirms inside a dialog, and let its label name the act.
Destructive actions
<button type="button" class="btn btn-danger">Delete</button><button type="button" class="btn btn-primary btn-danger">Delete project</button><button type="button" class="btn btn-primary btn-danger" disabled>Delete project</button>#Sizes
The default height is 38px, with 32px for dense UI and 44px for prominent actions. Padding, label size, icon size and radius change together. On touch screens every size grows to at least 44px.
Sizes
<button type="button" class="btn btn-sm">Small</button><button type="button" class="btn">Medium</button><button type="button" class="btn btn-lg">Large</button>#With icons
Put icon on the icon itself. The button sets its size, 16px by default, 14px in small and 18px in large buttons, at a 1.5 stroke. btn-square makes a square button: give it an accessible name with aria-label.
With icons
<button type="button" class="btn btn-primary"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M12 5v14M5 12h14" /> </svg>New project</button><button type="button" class="btn btn-square" aria-label="Search"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <circle cx="11" cy="11" r="6" /> <path d="m20 20-4.35-4.35" /> </svg></button><button type="button" class="btn btn-quiet btn-square" aria-label="More"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <circle cx="5" cy="12" r="1" /> <circle cx="12" cy="12" r="1" /> <circle cx="19" cy="12" r="1" /> </svg></button>#Pill
btn-pill rounds the ends fully and adds a little inline space, since a round end feels tighter than a flat one.
Pill
<button type="button" class="btn btn-pill">Follow</button><button type="button" class="btn btn-primary btn-pill">Subscribe</button>#Toggle
A quiet button with aria-pressed="true" stays sunk into a well. Update the attribute with your own script. A quiet button also stays sunk, without script, while the menu or popover placed right after it is open.
Toggle
<button type="button" class="btn btn-quiet btn-square" aria-label="Bold" aria-pressed="true"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M7 5h6a3.5 3.5 0 0 1 0 7H7zM7 12h7a3.5 3.5 0 0 1 0 7H7z" /> </svg></button><button type="button" class="btn btn-quiet btn-square" aria-label="Italic" aria-pressed="false"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M11 5h6M7 19h6M14 5l-4 14" /> </svg></button>#Group
btn-group joins related actions into one outer shape. Each button keeps its own material; the group squares the corners that meet and lets neighboring contours overlap into a single seam. A button in a group does not lift on its own, so the shape stays whole. Give the group role="group" and a label.
Group
<div class="btn-group" role="group" aria-label="History"> <button type="button" class="btn">Undo</button> <button type="button" class="btn">Redo</button></div><div class="btn-group" role="group" aria-label="Deploy"> <button type="button" class="btn btn-primary">Deploy</button> <button type="button" class="btn btn-primary btn-square" aria-label="Deploy options"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="m6 9 6 6 6-6" /> </svg> </button></div>The second button of a split action usually opens a menu: add popovertarget and the menu places itself against it.
#Pagination
A row of quiet square buttons makes page links. The current page has aria-current="page" and stays sunk into a well, like a pressed toggle.
Pagination
<nav class="flex items-center gap(2)" aria-label="Pagination"> <a class="btn btn-quiet btn-square btn-sm" href="#page-1" aria-label="Previous page"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="m15 6-6 6 6 6" /> </svg> </a> <a class="btn btn-quiet btn-square btn-sm" href="#page-1">1</a> <a class="btn btn-quiet btn-square btn-sm" href="#page-2" aria-current="page">2</a> <a class="btn btn-quiet btn-square btn-sm" href="#page-3">3</a> <a class="btn btn-quiet btn-square btn-sm" href="#page-3" aria-label="Next page"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="m9 6 6 6-6 6" /> </svg> </a></nav>#Busy
Set aria-busy="true" while an action runs. The button keeps its label and material, stops lifting and shows an inline spinner sized like its icons. Change the label to say what is happening, and ignore further activation in your handler.
Busy
<button type="button" class="btn" aria-busy="true"> <span class="spinner spinner-inline" aria-hidden="true"></span>Saving…</button><button type="button" class="btn btn-primary" aria-busy="true"> <span class="spinner spinner-inline" aria-hidden="true"></span>Publishing…</button>#Disabled
A disabled button drops back into the surface: a flat well with disabled ink. Links cannot be disabled; use aria-disabled="true" and remove the href.
Disabled
<button type="button" class="btn" disabled>Default</button><button type="button" class="btn btn-primary" disabled>Primary</button>#Adjust one instance
Utilities win over component styles because the utilities layer comes after components:
Full width
<button type="button" class="btn btn-primary btn-lg w-full">Continue</button>#Classes
| Class | Description |
|---|---|
btn | The raised base button |
btn-primary | Ink on moonstone, pearl on obsidian: the main action of a view. With btn-danger it fills with the danger hue to confirm a destructive act. With btn |
btn-quiet | No material until touched, for toolbars, headers and dense rows. With btn |
btn-brand | The one hued control, filled from --color-brand; at most one per view. With btn |
btn-danger | The danger ink on the label of a destructive action. With btn |
btn-sm | 32px tall; the default is 38px. With btn |
btn-lg | 44px tall; the default is 38px. With btn |
btn-square | A square button for one icon; it needs an accessible name. With btn |
btn-pill | Fully rounded ends. With btn |
btn-group | A container that joins its buttons into one shape |
#Custom properties
| Property | Default | Description |
|---|---|---|
--btn-height | 2.375rem | Minimum block size |
--btn-padding-x | 1rem | Inline padding |
--btn-gap | .5rem | Space between icon and label |
--btn-font-size | .84375rem | Label size |
--btn-radius | var(--radius-control) | Corner radius: 10px, with 8px for small and 12px for large buttons |
--icon-size | 1rem | Size of an icon inside the button |