# Button

Triggers an action or an event, such as submitting a form, opening a dialog or deleting a record.

```tsx
import { Button } from "@zenoxai/ui/components/button"

function ButtonDemo() {
  return <Button>Save changes</Button>
}
```

## Usage

```tsx
import { Button } from "@zenoxai/ui/components/button"

<Button onClick={save}>Save changes</Button>
```

Use one `default` (primary) button per view for the main action. Everything else is `outline`,
`secondary` or `ghost`. Write labels as a verb plus an object ("Save changes", "Delete alert"),
in sentence case.

## Variants

```tsx
import { Button } from "@zenoxai/ui/components/button"

function ButtonVariants() {
  return (
    <>
      <Button>Default</Button>
      <Button variant="secondary">Secondary</Button>
      <Button variant="outline">Outline</Button>
      <Button variant="ghost">Ghost</Button>
      <Button variant="destructive">Destructive</Button>
      <Button variant="link">Link</Button>
    </>
  )
}
```

| Variant       | Use for                                                        |
| ------------- | -------------------------------------------------------------- |
| `default`     | The primary action of the view. One per view.                  |
| `secondary`   | A supporting action next to the primary one.                   |
| `outline`     | Actions in toolbars, filters and dialogs.                      |
| `ghost`       | Low-emphasis actions in dense areas: table rows, icon buttons. |
| `destructive` | Irreversible actions. Confirm them with `confirm()` first.     |
| `link`        | An action that reads as inline text.                           |

## Sizes

`default` (32px) is the size for forms and toolbars. `sm` (28px) and `xs` (24px) fit dense
tables and filter bars; `lg` (36px) is for empty states and landing surfaces. Input, Select,
Native Select, Number Input, Input Group and Combobox share the `sm`, `default` and `lg`
heights, so a button and a field of the same size line up.

The icon follows the size name: 12px at `xs`, 14px at `sm`, 16px at `default` and `lg`, in
the square `icon-*` sizes too.

```tsx
import { Button } from "@zenoxai/ui/components/button"

function ButtonSizes() {
  return (
    <>
      <Button size="xs">Extra small</Button>
      <Button size="sm">Small</Button>
      <Button>Default</Button>
      <Button size="lg">Large</Button>
    </>
  )
}
```

## With an icon

Mark the icon with `data-icon="inline-start"` or `data-icon="inline-end"` so the button
tightens the padding on that side. An icon-only button uses an `icon*` size and must have an
`aria-label`.

```tsx
import { ArrowRightIcon, PlusIcon, Trash2Icon } from "lucide-react"
import { Button } from "@zenoxai/ui/components/button"

function ButtonWithIcon() {
  return (
    <>
      <Button>
        <PlusIcon data-icon="inline-start" />
        New alert
      </Button>
      <Button variant="outline">
        Continue
        <ArrowRightIcon data-icon="inline-end" />
      </Button>
      <Button variant="ghost" size="icon" aria-label="Delete alert">
        <Trash2Icon />
      </Button>
    </>
  )
}
```

## Loading

Disable the button, set `aria-busy="true"` and put a `Spinner` in place of the icon while the
action runs. A disabled button is dimmed to 50%; a busy one is not, so it reads as working
rather than unavailable. Keep the label: it tells the user what is in progress.

```tsx
import { Button } from "@zenoxai/ui/components/button"
import { Spinner } from "@zenoxai/ui/components/spinner"

function ButtonLoading() {
  return (
    <Button disabled aria-busy="true">
      <Spinner data-icon="inline-start" aria-hidden />
      Saving
    </Button>
  )
}
```

## As a link

Navigation uses a link, not a button. To get the button look on a link, give the `<a>` the
classes from `buttonVariants()`. Do not render an `<a>` through Button's `render` prop: Base UI
then gives it `role="button"`, and screen readers announce a button that navigates.

```tsx
import { buttonVariants } from "@zenoxai/ui/components/button"

function ButtonAsLink() {
  return (
    <a href="#usage" className={buttonVariants({ variant: "outline" })}>
      Read the usage notes
    </a>
  )
}
```

## Accessibility

- A disabled button is removed from the tab order. Set `focusableWhenDisabled` when the user
  must still be able to reach it, for example to read a tooltip that explains why.
- `buttonVariants()` returns the classes alone. Use it to give a link the button look; the
  element keeps its own role.

## API reference

`import { ... } from "@zenoxai/ui/components/button"`

### Button

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| focusableWhenDisabled | `boolean` | `false` | Whether the button should be focusable when disabled. |
| nativeButton | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`). |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, ButtonState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |
| size | `"default" \| "xs" \| "sm" \| "lg" \| "icon" \| "icon-xs" \| "icon-sm" \| "icon-lg" \| null` | `default` | Height: `xs` 24px, `sm` 28px, `default` 32px, `lg` 36px. The `icon-*` sizes are square buttons of the same heights for a single icon. The icon follows the size name: 12px at `xs`, 14px at `sm`, 16px at `default` and `lg`. |
| variant | `"link" \| "default" \| "destructive" \| "outline" \| "secondary" \| "ghost" \| null` | `default` | Visual weight. `default` is the filled primary action, one per view; `outline` and `secondary` are for the other actions; `ghost` has no fill until hover, for toolbars and icon buttons; `destructive` is for delete and other irreversible actions; `link` looks like inline text. |

