Skip to content

Buttons

<button class="btn btn-primary">Primary</button>
<button class="btn btn-secondary">Secondary</button>
<button class="btn btn-ghost">Ghost</button>
<button class="btn btn-danger">Danger</button>
<button class="btn btn-primary btn-sm">Small</button>
<button class="btn btn-primary">Medium</button>
<button class="btn btn-primary btn-lg">Large</button>
<button class="btn btn-primary" disabled>Disabled</button>
<button class="btn btn-secondary" disabled>Disabled</button>

.btn-loading paints a spinner in place of the leading icon and freezes interaction. The React loading prop also sets disabled and aria-busy="true".

<button
class="btn btn-primary btn-loading"
type="button"
disabled
aria-busy="true"
>
Saving
</button>
<button
class="btn btn-secondary btn-loading"
type="button"
disabled
aria-busy="true"
>
Loading
</button>

If you pass both icon and loading, the leading icon is suppressed. A trailing icon stays visible.

<button class="btn btn-primary btn-full-width">Continue</button>

The .btn classes apply to <a> for navigation. In React, pass render={<a href="…" />} and nativeButton={false} so Base UI’s keyboard and ARIA wiring adjust.

<a href="/orders/new" class="btn btn-primary">New order</a>
<a href="/reports" class="btn btn-secondary">View reports</a>

disabled doesn’t apply to anchors — omit the link (or render plain text) instead of styling a non-interactive link as disabled.

Pass icon for a leading icon or iconTrailing for a trailing one — rendered at size={16} with aria-hidden. See Icons.

<button class="btn btn-primary">
<i class="ti ti-plus" aria-hidden="true"></i>
New order
</button>
<button class="btn btn-secondary">
Export
<i class="ti ti-download" aria-hidden="true"></i>
</button>
<button class="btn btn-danger">
<i class="ti ti-trash" aria-hidden="true"></i>
Delete
</button>

Drop the label and pass aria-label for a square button — table row controls, toolbar icons, dismiss. The React wrapper adds .btn-square automatically when a button has an icon but no children; vanilla callers add the class themselves.

<button
class="btn btn-ghost btn-square"
type="button"
aria-label="More actions"
>
<i class="ti ti-dots-vertical" aria-hidden="true"></i>
</button>
<button
class="btn btn-secondary btn-square btn-sm"
type="button"
aria-label="Edit"
>
<i class="ti ti-pencil" aria-hidden="true"></i>
</button>
<button
class="btn btn-danger btn-square btn-lg"
type="button"
aria-label="Delete"
>
<i class="ti ti-trash" aria-hidden="true"></i>
</button>

Wrap multiple .btn children in .btn-group to render them as one segmented unit: shared borders, rounded outer corners, square inner corners. Presentational only — each child is an independently focusable button. For single-select toggles, reach for a dedicated segmented control.

<div class="btn-group">
<button class="btn btn-secondary">Day</button>
<button class="btn btn-secondary">Week</button>
<button class="btn btn-secondary">Month</button>
</div>
<div class="btn-group btn-group-vertical">
<button class="btn btn-secondary">Up</button>
<button class="btn btn-secondary">Center</button>
<button class="btn btn-secondary">Down</button>
</div>

A row-action menu stacked into a sidebar — mixed variants, leading icons, primary on top, destructive at the bottom.

<div class="btn-group btn-group-vertical">
<button class="btn btn-primary">
<i class="ti ti-pencil" aria-hidden="true"></i>
Edit
</button>
<button class="btn btn-secondary">
<i class="ti ti-copy" aria-hidden="true"></i>
Duplicate
</button>
<button class="btn btn-secondary">
<i class="ti ti-archive" aria-hidden="true"></i>
Archive
</button>
<button class="btn btn-danger">
<i class="ti ti-trash" aria-hidden="true"></i>
Delete
</button>
</div>