# Button

> A clear, responsive action with quiet secondary states.

Component · Free · https://lodeui.com/components/button

## When to use

- The main or secondary action in a form, dialog, card or toolbar.
- Async actions that need a loading state without the button changing width.
- Icon-only actions in dense toolbars, with an aria-label.

## When not to use

- Navigating to another page: render a link styled with buttonVariants() instead.
- Picking one option from a few: use a segmented control or radio group.
- An action whose result should show in place (Saved, Failed): use the action button.

## Installation

```bash
npx shadcn@latest add https://lodeui.com/r/button.json
```

## Usage

```tsx title="example.tsx"
import { Button } from "@/components/ui/button";

export function SaveBar({ pending, onSave }: { pending: boolean; onSave: () => void }) {
  return (
    <div className="flex justify-end gap-2">
      <Button variant="ghost">Discard</Button>
      <Button loading={pending} onClick={onSave}>Save changes</Button>
    </div>
  );
}
```

## API reference

### Button

A native button with five visual weights, five sizes and a loading state. All other button attributes pass through.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| variant | `"primary" \| "secondary" \| "outline" \| "ghost" \| "destructive"` | `"primary"` | Visual weight. Use one primary per view. |
| size | `"sm" \| "md" \| "lg" \| "icon" \| "icon-sm"` | `"md"` | Height and padding. Icon sizes are square. |
| loading | `boolean` | `false` | Shows a spinner, disables the button and keeps its width so the layout doesn't jump. |
| type | `"button" \| "submit" \| "reset"` | `"button"` | Defaults to button so it never submits a form by accident. |
| ...props | `ButtonHTMLAttributes<HTMLButtonElement>` | – | onClick, disabled, aria-* and anything else a button accepts. |

### buttonVariants

Returns the button class string, for links and other elements that should look like a button.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| options | `{ variant?; size?; className? }` | – | Same variant and size values as Button. |

## Keyboard interactions

| Keys | Action |
| --- | --- |
| Enter / Space | Activates the button |
| Tab | Moves focus to and from the button |

## Accessibility

- Renders a real <button>, so it is focusable and announced as a button.
- Loading sets aria-busy and disables the control; the label stays in the DOM for screen readers.
- Icon-only buttons need an aria-label. The focus ring meets contrast on both themes.

## Motion

- Scales to 97% while pressed over 150ms ease-out.
- Hover only changes color, so dense toolbars stay calm.

## Responsive behavior

- Sizes are fixed heights (32, 40, 48px), so buttons line up in any layout.
- Text never wraps; pair long labels with a wider container or the sm size on phones.
- Use w-full on mobile for primary actions at the bottom of forms.

## Performance

- No JavaScript beyond React: hover and press are CSS transitions.
- buttonVariants is a pure function you can call on the server.

## Notes for AI

- Use variant="primary" once per view; secondary or ghost for the rest.
- Pass loading instead of swapping the label for a spinner yourself.
- For links, use <Link className={buttonVariants({ variant: "outline" })}>, not <Button onClick={router.push}>.

## Related

- [Action button](https://lodeui.com/components/action-button) — A button that morphs through saving, saved and failed, right where you clicked.
- [Dropdown menu](https://lodeui.com/components/dropdown-menu) — Actions, checkboxes and radio options in a springy menu with full keyboard support.
- [Segmented control](https://lodeui.com/components/segmented-control) — A compact single choice with a pill that slides to the selection.
- [Tooltip](https://lodeui.com/components/tooltip) — A small label on hover or focus, with a delay that respects intent.
