Button
Actions and navigation with shared intents, variants, sizes, and a loading state.
.btnis for actionable elements:<button>,<a href>, orinput[type="button"|"submit"|"reset"]. Not a decorative box class.- Use a real
<button>for actions. - Use
<a class="btn">for navigation. - Always set
type="button"when a button is not submitting a form. - Supports shared intents, shared variants, button-only variants, and sizes.
- Adds button-only
.ghostand.linkvariants. - Button groups use
.jointo visually join adjacent buttons. - Use
aria-pressedfor toggle buttons. Actual styles the pressed state; application code owns changing the attribute. - Disable a
<button>or<input>with the nativedisabledattribute. Anchors have no native disabled state, so<a class="btn" aria-disabled="true">is the supported way to disable a link button; application code must also prevent the click sincearia-disableddoes not stop navigation on its own.
<button type="button">Unstyled</button>
<button class="btn" type="button">Default</button>
<button class="btn secondary" type="button">Secondary</button>
<button class="btn danger" type="button">Danger</button>
<button class="btn outline" type="button">Outline</button>
<button class="btn danger outline" type="button">Danger outline</button>
<button class="btn soft" type="button">Soft</button>
<button class="btn danger soft" type="button">Danger soft</button>
<button class="btn ghost" type="button">Ghost</button>
<a class="btn primary" href="/account">Account</a>
<button class="btn link" type="button">Button as link</button>
<button class="btn primary" type="button" aria-busy="true" disabled>
<span class="spinner" aria-hidden="true"></span>
Loading
</button>
<button class="btn primary" type="button" aria-busy="true">In progress</button>
<button class="btn" type="button" disabled>Disabled</button>
<a class="btn outline" href="/account" aria-disabled="true">Disabled link</a>
Button group using .join
<div class="join" role="group" aria-label="Text alignment">
<button class="btn" type="button">Left</button>
<button class="btn outline" type="button">Center</button>
<button class="btn soft" type="button">Right</button>
</div>
Toggle buttons
<button class="btn" type="button" aria-pressed="false" data-demo-toggle>
Bold
</button>
<div class="join" role="group" aria-label="Text alignment" data-demo-toggle-group="single">
<button class="btn" type="button" aria-pressed="true">Left</button>
<button class="btn outline" type="button" aria-pressed="false">Center</button>
<button class="btn outline" type="button" aria-pressed="false">Right</button>
</div>
for (const button of document.querySelectorAll("[data-demo-toggle]")) {
button.addEventListener("click", () => {
const pressed = button.getAttribute("aria-pressed") === "true";
button.setAttribute("aria-pressed", String(!pressed));
});
}
for (const group of document.querySelectorAll('[data-demo-toggle-group="single"]')) {
group.addEventListener("click", (event) => {
const button = event.target.closest("button[aria-pressed]");
if (!button || !group.contains(button)) return;
for (const item of group.querySelectorAll("button[aria-pressed]")) {
item.setAttribute("aria-pressed", String(item === button));
}
});
}
Size variants
<button class="btn sm" type="button">Small</button>
<button class="btn" type="button">Regular</button>
<button class="btn lg" type="button">Large</button>
With icons, loading state...
<button class="btn" type="button"><i class="ti ti-star"></i> With an icon</button>
<button class="btn primary" type="button" aria-busy="true" disabled>
<span class="spinner" aria-hidden="true"></span>
Saving…
</button>