Quire UI
Controls10

Button

Loading without layout shift, shortcuts, tooltips and a built-in confirm step.

Installation

npx shadcn@latest add @quireui/button

Usage

<Button variant="primary" onClick={save}>
  Save changes
</Button>

Variants and sizes

variant: primary, secondary (default), ghost, danger. size: sm, md (default), lg, icon. Sizes follow the density setting.

Loading

loading disables the button and keeps its width. The spinner only appears if loading takes longer than 150ms, so fast actions never flash one.

The quick one never shows a spinner. Neither button changes width.

<Button variant="primary" loading={saving} onClick={save}>
  Save changes
</Button>

Shortcut

shortcut shows the key hint and binds it on the page. mod is ⌘ on Apple devices and Ctrl elsewhere. Shortcuts without a modifier never fire while someone is typing.

Press the shortcut anywhere on the page. Saved 0 times.

<Button variant="primary" shortcut="mod+s" onClick={save}>
  Save
</Button>

Tooltip

tooltip shows on hover and focus. On icon buttons it also becomes the accessible label, so they can't ship unlabelled, and the shortcut moves into the tooltip.

<Button size="icon" variant="ghost" tooltip="Bold" shortcut="mod+b">
  <TextBIcon />
</Button>

Confirm

confirm adds a second step without a dialog. The first click swaps to the confirm label, the second runs onClick. It resets after 3 seconds, on blur, or with Esc. Both labels share one space, so the button never changes width.

3 invoices left.

<Button variant="danger" confirm="Click again to delete" onClick={remove}>
  <TrashIcon /> Delete invoice
</Button>

Changing labels

For labels that change on their own, pair the button with the optional Text morph.

<Button onClick={toggle}>
  <TextMorph>{following ? "Following" : "Follow"}</TextMorph>
</Button>

Accessibility

It is a native button. While loading it is marked busy and keeps its label, so screen readers never hear it go blank. An icon-only button takes its name from tooltip, and a shortcut is exposed as aria-keyshortcuts.

KeyAction
Enter / SpaceRuns onClick. With confirm, the first press arms the button and the second runs it.
EscCancels an armed confirm step.
TabMoves focus. Leaving the button also cancels an armed confirm step. A loading button stays in the tab order.
The shortcut keysClicks the button from anywhere on the page. Shortcuts without a modifier never fire while someone is typing.

API reference

Button

Prop

Type

Also takes every prop of Base UI's Button. Style it with [data-slot="button"].

On this page