v0.5.1

Button

Interactive button for actions and form submissions.

Installation

npx paubha@latest add button

Usage

import { Button } from "@/components/ui/button";

<Button>Save changes</Button>
<Button variant="secondary">Cancel</Button>
<Button destructive>Delete</Button>

Examples

Variants

Primary, secondary, tertiary, and link.

Destructive

destructive is independent of variant, so every hierarchy has a destructive form. It swaps to error colors and uses the glow-focus-error focus ring.

Sizes

sm 32px · md 40px · lg 48px · xl 56px · 2xl 64px.

With icon

leadingIcon accepts any element and sizes it automatically to match the button: 16px at sm, 20px at md/lg, 24px at xl/2xl. It's a decorative slot: the icon is marked aria-hidden for you.

States

loading shows a spinner, sets aria-busy, and disables the button, independent of the disabled prop, so a button can be disabled without being in a loading state.

API reference

PropTypeDefaultDescription
variant"primary" | "secondary" | "tertiary" | "link""primary"Visual hierarchy.
destructivebooleanfalseDestructive intent, combinable with any variant. Switches to error colors and the glow-focus-error ring.
size"sm" | "md" | "lg" | "xl" | "2xl""md"Density: 32 / 40 / 48 / 56 / 64px height.
leadingIconReactNode—Instance-swap icon slot rendered before the label, auto-sized to match the button's size (16px sm, 20px md/lg, 24px xl/2xl).
loadingbooleanfalseShows a spinner, sets aria-busy, and disables the button.
disabledbooleanfalsePrevents interaction.

Accessibility

Accessibility

  • Role. Native <button>, so role="button" and keyboard activation (Enter/Space) come from the browser, not manual ARIA.

  • Focus. Visible glow-focus ring on Tab, via focus-visible (glow-focus-error when destructive). Never shown on a pointer click.

  • Disabled. The native disabled attribute prevents all interaction, including from loading.

  • Loading. aria-busy="true" announces the busy state to screen readers while the spinner is visible.