# Button

**`sonic-button`** is the clickable control of the library: a plain button, a link when `href` is set, or a form toggle when it has a `name` and `value`. It shares `type` / `variant` / `size` with **`sonic-badge`**, and exposes `prefix` / `suffix` slots for icons.

## Type

With no `type`, the button is `default`. Use `custom` with `--sc-btn-custom-color` and `--sc-btn-custom-bg` for a one-off color.

<sonic-code>
  <template>
    <div class="flex flex-wrap gap-2">
      <sonic-button>Default</sonic-button>
      <sonic-button type="primary">Primary</sonic-button>
      <sonic-button type="neutral">Neutral</sonic-button>
      <sonic-button type="warning">Warning</sonic-button>
      <sonic-button type="info">Info</sonic-button>
      <sonic-button type="success">Success</sonic-button>
      <sonic-button type="danger">Danger</sonic-button>
      <sonic-button type="custom" style="--sc-btn-custom-color: #fde68a; --sc-btn-custom-bg: #5b21b6">Custom</sonic-button>
    </div>
  </template>
</sonic-code>

## Variant

With no `variant`, the button is filled. The `outline` / `ghost` / `link` variants take their color from `type`. `unstyled` removes all styling so you can apply your own classes.

<sonic-code>
  <template>
    <div class="flex flex-wrap gap-2">
      <sonic-button type="primary">Default</sonic-button>
      <sonic-button type="primary" variant="outline">Outline</sonic-button>
      <sonic-button type="primary" variant="ghost">Ghost</sonic-button>
      <sonic-button type="primary" variant="link">Link</sonic-button>
      <sonic-button variant="unstyled">Unstyled</sonic-button>
    </div>
  </template>
</sonic-code>

## Size

With no `size`, the button is `md`.

<sonic-code>
  <template>
    <div class="flex flex-wrap items-center gap-2">
      <sonic-button size="2xs">2xs</sonic-button>
      <sonic-button size="xs">xs</sonic-button>
      <sonic-button size="sm">sm</sonic-button>
      <sonic-button>md</sonic-button>
      <sonic-button size="lg">lg</sonic-button>
      <sonic-button size="xl">xl</sonic-button>
      <sonic-button size="2xl">2xl</sonic-button>
    </div>
  </template>
</sonic-code>

## Shape

`circle` and `square` make a fixed-size icon button. `block` stretches to the full width of the parent.

<sonic-code>
  <template>
    <div class="flex flex-wrap items-center gap-2 mb-2">
      <sonic-button shape="circle" type="primary"><sonic-icon library="iconoir" name="plus"></sonic-icon></sonic-button>
      <sonic-button shape="square" type="primary"><sonic-icon library="iconoir" name="plus"></sonic-icon></sonic-button>
    </div>
    <sonic-button shape="block" type="primary">Block</sonic-button>
  </template>
</sonic-code>

## Prefix and suffix slots

<sonic-code>
  <template>
    <div class="flex flex-wrap gap-2">
      <sonic-button type="primary" variant="outline">
        <sonic-icon library="iconoir" slot="prefix" name="arrow-left"></sonic-icon>
        Previous flight
      </sonic-button>
      <sonic-button type="primary">
        Next flight
        <sonic-icon library="iconoir" slot="suffix" name="arrow-right"></sonic-icon>
      </sonic-button>
    </div>
  </template>
</sonic-code>

## Loading

`loading` replaces the content with a spinner and blocks clicks. The button keeps the width of its content.

<sonic-code>
  <template>
    <div class="flex flex-wrap gap-2">
      <sonic-button loading></sonic-button>
      <sonic-button loading>Loading button</sonic-button>
      <sonic-button loading type="primary">
        <sonic-icon library="iconoir" slot="prefix" name="check"></sonic-icon>
        Checking in
      </sonic-button>
    </div>
  </template>
</sonic-code>

## Link

With `href`, the button renders as a link. For a relative `href`, the button gets `active` when the current URL matches, according to `autoActive` (default `partial`). Add `pushState` to navigate without reloading the page.

<sonic-code>
  <template>
    <div class="flex flex-wrap gap-2">
      <sonic-button href="https://example.com" target="_blank" type="primary">External link</sonic-button>
      <sonic-button href="/core/components/ui/button" variant="ghost">Current page</sonic-button>
    </div>
  </template>
</sonic-code>

## Toggle and radio

A button with `name` and `value` writes to its `formDataProvider` and toggles `active` when clicked. Add `radio` for a single choice in a group, or `unique` to also allow deselecting. Children marked `swap="on"` / `swap="off"` show only in the active / inactive state.

<sonic-code>
  <template>
    <div class="flex flex-wrap items-center gap-4">
      <sonic-button formDataProvider="button-toggle-demo" name="visible" value="yes" type="primary" shape="circle" variant="outline">
        <sonic-icon library="iconoir" swap="on" name="eye-empty"></sonic-icon>
        <sonic-icon library="iconoir" swap="off" name="eye-off"></sonic-icon>
      </sonic-button>
      <sonic-group formDataProvider="button-radio-demo">
        <sonic-button radio minWidth="7rem" name="plan" value="free">Free</sonic-button>
        <sonic-button radio minWidth="7rem" name="plan" value="pro">Pro</sonic-button>
        <sonic-button radio minWidth="7rem" name="plan" value="team">Team</sonic-button>
      </sonic-group>
    </div>
  </template>
</sonic-code>

## Reset

`reset` clears the button's own `formDataProvider`. Give it a value to clear another one by name.

<sonic-code>
  <template>
    <div formDataProvider="button-reset-demo" class="mb-2">
      <sonic-checkbox name="agree" value="yes">Extra baggage</sonic-checkbox>
      <sonic-button reset>Reset this form</sonic-button>
    </div>
    <sonic-button reset="button-reset-demo">Reset by name</sonic-button>
  </template>
</sonic-code>

## Go back

`goBack` navigates back in history. When there is no previous page on the same origin, it goes to the attribute value, or to the site root if empty.

<sonic-code>
  <template>
    <sonic-button goBack="/" variant="outline">
      <sonic-icon library="iconoir" slot="prefix" name="arrow-left"></sonic-icon>
      Back
    </sonic-button>
  </template>
</sonic-code>

## Accessibility

Icon-only buttons need a label. Use `data-aria-label`, which is forwarded to the inner `button` (and link).

<sonic-code>
  <template>
    <sonic-button shape="circle" data-aria-label="Close">
      <sonic-icon library="iconoir" name="cancel"></sonic-icon>
    </sonic-button>
  </template>
</sonic-code>

## API reference

| Attribute | Values | Description |
|----------|---------|-------------|
| `type` | `default` (default) · `primary` · `neutral` · `warning` · `info` · `success` · `danger` · `custom` | Color; `custom` reads `--sc-btn-custom-color` and `--sc-btn-custom-bg` |
| `variant` | `default` (default) · `outline` · `ghost` · `link` · `unstyled` | Visual style |
| `size` | `2xs` … `2xl` (default `md`) · `inherit` | Typography and padding |
| `shape` | `default` (default) · `circle` · `square` · `block` | Icon button or full width |
| `icon` | boolean | Enlarges a lone icon |
| `loading` | boolean | Shows a spinner and blocks clicks |
| `disabled` | boolean | Dims the button and blocks clicks |
| `active` | boolean | Active state, set automatically for links and toggles |
| `align` | `left` · `center` · `right` | Text alignment |
| `direction` | flex direction (default `row`) | Layout of slots |
| `alignItems` | flex `align-items` (default `center`) | Cross-axis alignment of slots |
| `justify` | flex `justify-content` (default `center`) | Main-axis alignment of slots |
| `minWidth` | CSS length (default `0`) | Minimum width of the button |
| `href` | URL | Renders the button as a link |
| `target` | `_self` · `_blank` · `_parent` · `_top` | Link target |
| `download` | string | Link `download` attribute |
| `pushState` | boolean | Navigates with `history.pushState` |
| `autoActive` | `partial` (default) · `strict` · `strict-path-only` · `disabled` | URL matching for `active` |
| `goBack` | URL or empty | Goes back in history, with a fallback URL |
| `reset` | empty or provider name | Clears the current or named form data provider |
| `name` / `value` | string | Form field written to the data provider |
| `formDataProvider` | string | Data provider to write to (default: nearest ancestor) |
| `radio` | boolean | Single choice among buttons with the same `name` |
| `unique` | boolean | Like `radio`, but can be deselected |
| `autoRepeat` | boolean | Repeats the click while the pointer is held |
| `data-aria-label` | string | `aria-label` of the inner button |
| `data-aria-labelledby` | string | `aria-labelledby` of the inner button |
| `data-aria-controls` | string | `aria-controls` of the inner button |
| `data-aria-expanded` | boolean | `aria-expanded` of the inner button |

| Slot | Description |
|------|-------------|
| *(default)* | Label |
| `prefix` | Icon or text before the label |
| `suffix` | Icon or text after the label |
