# xpl-button

Buttons allow users to take an action with clear visual hierarchy (variant), semantic meaning (sentiment), and size.

## Usage

> [!IMPORTANT]
> Older props such as `state` still work, but we recommend using the sentiment described below.


### Basic button

Pass button text via the default slot (same as native `<button>`):

```html
<xpl-button>Primary action</xpl-button>
```

### Variant and sentiment

Use `variant` for style (primary, secondary, tertiary) and `sentiment` for intent (default, positive, negative):

```html
<xpl-button variant="secondary">Secondary</xpl-button>
<xpl-button variant="tertiary" sentiment="positive">Positive action</xpl-button>
<xpl-button sentiment="negative">Destructive</xpl-button>
```

### Size

Use **`size`** for button size: `default`, `sm` (small), or `xs` (extra small):

```html
<xpl-button size="sm">Small</xpl-button>
<xpl-button size="xs">Extra small</xpl-button>
```

### Icon from Apollo icon library

Use `icon` with a name from the xpl-icon library; use `icon-position` to place the icon at start or end:

```html
<xpl-button icon="download" icon-position="end">
  Download
</xpl-button>
```

### Icon-only button

Use `icon-only` when the button shows only an icon (no label). Always set `icon` and use a descriptive `aria-label` on the host or inner button for accessibility:

```html
<xpl-button icon-only icon="x" aria-label="Close"></xpl-button>
```

### Loading state

When `is-loading` is true, the button shows a spinner, hides the label and icon, stays the same size, and is non-interactive:

```html
<xpl-button is-loading>Submitting</xpl-button>
```

### Form submission

The component renders a native `<button>`. Use `type` (`submit`, `reset`, or `button`), `name`, `value`, and `form` for form behaviour:

```html
<form id="my-form">
  <xpl-button type="submit" name="action" value="save">Save</xpl-button>
</form>
```

### Disabled

Use the `disabled` prop to disable the button (same as native `disabled`):

```html
<xpl-button disabled>Disabled</xpl-button>
```

## DOM classes

The host element includes BEM-style classes, including:

- **Size:** `xpl-button--default` | `xpl-button--sm` | `xpl-button--xs`
- **Variant:** `xpl-button--primary` | `xpl-button--secondary` | `xpl-button--tertiary` (and `xpl-button--subtle` while that value is still supported)
- **Sentiment:** `xpl-button--neutral` | `xpl-button--positive` | `xpl-button--negative` when using `sentiment`
- **Deprecated `state`:** if set, legacy classes `xpl-button--neutral` | `xpl-button--warning` | `xpl-button--success` are applied instead of the sentiment-based classes above (see migration)

Prefer targeting **`sentiment`** + **`variant`** + **`size`** in new code; avoid relying on deprecated `state` class names for new selectors.

## Migration Notes:

The class **`xpl-button--default`** on the host continues to mean **size** (`size="default"`), not sentiment.

### Deprecated `state` prop

The **`state`** prop (`neutral` | `warning` | `success`) is deprecated. Use **`sentiment`** instead:

| Old `state`   | New `sentiment` |
| ------------- | ----------------- |
| `neutral`     | `neutral` (default) |
| `warning`     | `negative`        |
| `success`     | `positive`        |

**Backward compatibility:** if **`state`** is set, it controls the sentiment segment of the host class list (`xpl-button--neutral`, `xpl-button--warning`, `xpl-button--success`) so existing styles or tests that key off those class names can keep working. New work should use **`sentiment`** only (`neutral` | `negative` | `positive`).

### Deprecated `variant="subtle"` → `tertiary`

**`variant="subtle"`** is deprecated and retained only for backward compatibility, applying the **`xpl-button--subtle`** class. Use **`variant="tertiary"`** instead, which applies **`xpl-button--tertiary`**.

### Other API notes

- **`isLoading` / `is-loading`:** loading UI without forcing the disabled (gray) visual treatment.
- **`icon`**, **`icon-position`**, **`icon-only`:** use Apollo icon names; no inline SVGs required.
- **`data-*`, `aria-*`, and `role` on the host:** mirrored onto the inner `<button>` after render for accessibility and testing tools. After forwarding, these attributes are removed from the host element. Avoid relying on `role` on the host for external selectors.

## Guidelines

- **Pass button content via the default slot:** `<xpl-button>Save</xpl-button>`. Slots support rich content (formatted text, inline icons, etc.).
- Use **`iconOnly`** for icon-only buttons and provide an **`aria-label`** (or ensure the inner button has an accessible name).
- Use **`icon`** for icon names from the xpl-icon library; use **`icon-position`** to place the icon at start or end of the slot content.

## Accessibility

- The component renders a native `<button>`, so it is focusable and keyboard-activable by default.
- When **`is-loading`** is true, the inner button has `aria-busy="true"` and the loading spinner is marked **`aria-hidden="true"`** so the label remains the accessible name.
- For **icon-only** buttons, provide an accessible name via **`aria-label`** on the host (e.g. `<xpl-button icon-only icon="x" aria-label="Close">`) so screen readers announce the action.
- For **WAI-ARIA composite widgets** (like tabs), use the **`controlAttrs`** prop to apply `id`, `role`, `aria-controls`, `aria-selected`, and `aria-current` directly to the inner `<button>`. This is preferred over setting these attributes on the host, which would be forwarded and removed from the host.

<!-- Auto Generated Below -->


## Properties

| Property       | Attribute       | Description                                                                                                                                                                                                                            | Type                                                                                                                      | Default     |
| -------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ----------- |
| `controlAttrs` | --              | Attributes to apply to the inner native `<button>` (e.g., tab a11y wiring). Use this instead of setting `id` / `role` / `aria-*` on the host when the inner control is the element that needs them (e.g., WAI-ARIA composite widgets). | `{ id?: string; role?: string; 'aria-controls'?: string; 'aria-selected'?: "true" \| "false"; 'aria-current'?: string; }` | `undefined` |
| `disabled`     | `disabled`      | Whether button should be disabled                                                                                                                                                                                                      | `boolean`                                                                                                                 | `false`     |
| `form`         | `form`          | An optional form attribute for the button if type is submit                                                                                                                                                                            | `string`                                                                                                                  | `undefined` |
| `fullWidth`    | `full-width`    | Whether the button should be of full width as per parent container.                                                                                                                                                                    | `boolean`                                                                                                                 | `false`     |
| `icon`         | `icon`          | Icon to render - icon name as string (from xpl-icon library).                                                                                                                                                                          | `string`                                                                                                                  | `''`        |
| `iconOnly`     | `icon-only`     | When true, the button renders in icon-only circular style. Use for icon-only buttons.                                                                                                                                                  | `boolean`                                                                                                                 | `false`     |
| `iconPosition` | `icon-position` | Icon position relative to slot content. Ignored if no icon is provided.                                                                                                                                                                | `"end" \| "start"`                                                                                                        | `'start'`   |
| `isLoading`    | `is-loading`    | When true, shows a loading overlay with spinner over the button. Button is non-interactive.                                                                                                                                            | `boolean`                                                                                                                 | `false`     |
| `link`         | `link`          | whether button should yield a slot for a link tag                                                                                                                                                                                      | `boolean`                                                                                                                 | `undefined` |
| `name`         | `name`          | Name of the button, submitted with form data. Passed through to the native button element.                                                                                                                                             | `string`                                                                                                                  | `undefined` |
| `sentiment`    | `sentiment`     | Sentiment of the button, which applies different color schemes to indicate purpose/intent.                                                                                                                                             | `"negative" \| "neutral" \| "positive"`                                                                                   | `'neutral'` |
| `size`         | `size`          | Button size. Use 'default', 'xs' (extra small), or 'sm' (small).                                                                                                                                                                       | `"default" \| "sm" \| "xs"`                                                                                               | `'default'` |
| `state`        | `state`         | <span style="color:red">**[DEPRECATED]**</span> : Use `sentiment` with values "neutral", "negative", "positive" instead of `state` .<br/><br/>                                                                                         | `"neutral" \| "success" \| "warning"`                                                                                     | `undefined` |
| `type`         | `type`          | HTML button type attribute.                                                                                                                                                                                                            | `"button" \| "reset" \| "submit"`                                                                                         | `undefined` |
| `value`        | `value`         | Value of the button, submitted with form data. Passed through to the native button element.                                                                                                                                            | `string`                                                                                                                  | `undefined` |
| `variant`      | `variant`       | Button variant/style. Use "primary", "secondary", "tertiary" for new usage. "subtle" is deprecated but still supported for backward compatibility.                                                                                     | `"primary" \| "secondary" \| "subtle" \| "tertiary"`                                                                      | `'primary'` |


## Dependencies

### Used by

 - [xpl-banner](../xpl-banner)
 - [xpl-button-row](../xpl-button-row)
 - [xpl-list-item](../xpl-list/xpl-list-item)
 - [xpl-modal](../xpl-modal)
 - [xpl-side-nav](../xpl-side-nav)
 - [xpl-slideout](../xpl-slideout)
 - [xpl-spotlight](../xpl-spotlight)
 - [xpl-tab](../xpl-tab)
 - [xpl-top-nav](../xpl-top-nav)

### Depends on

- [xpl-icon](../xpl-icon)

### Graph
```mermaid
graph TD;
  xpl-button --> xpl-icon
  xpl-banner --> xpl-button
  xpl-button-row --> xpl-button
  xpl-list-item --> xpl-button
  xpl-modal --> xpl-button
  xpl-side-nav --> xpl-button
  xpl-slideout --> xpl-button
  xpl-spotlight --> xpl-button
  xpl-tab --> xpl-button
  xpl-top-nav --> xpl-button
  style xpl-button fill:#f9f,stroke:#333,stroke-width:4px
```

----------------------------------------------

*Built with [StencilJS](https://stenciljs.com/)*
