# Progress button

> A button that shows its action is running, and then whether it worked.

Source: https://contributors.home-assistant.io/design/components/progress-button/

Live demo of `ha-progress-button`.

```html
<ha-progress-button>Restart</ha-progress-button>
<ha-progress-button progress>Restart</ha-progress-button>
```

## Overview

A progress button is a [button](https://contributors.home-assistant.io/design/components/button/) for actions that take a moment and finish in place: saving a setting, running a test, calling an action. While the action runs, it shows a spinner. When it is done, it briefly shows a check mark on a green button, or an alert icon on a red one. After two seconds, it returns to normal.

## When to use

Use a progress button for:

- An action that takes a moment, where the result has nowhere else to show up, like **Test connection** or **Restart**

Don't use a progress button for:

- An action that opens a dialog or moves to another page. A regular [button](https://contributors.home-assistant.io/design/components/button/) is enough.
- Showing an error people need to read. The red flash says _that_ it failed, not _why_. Show the error as well, for example in an [alert](https://contributors.home-assistant.io/design/components/alert/).

## Anatomy

A progress button is a regular button with one extra layer:

1. **Button**: the regular button, with its container, optional icon, and label
2. **Spinner**: replaces the label while the action runs
3. **Result icon**: on top of the button after the action, a check mark for success or an alert icon for an error

## Variants

The progress button comes in the same appearances, variants, and sizes as a regular button, so it fits in next to one. During progress and while showing the result, it switches to the accent appearance.

Live demo of `ha-progress-button`.

```html
<ha-progress-button appearance="filled">Test</ha-progress-button>
<ha-progress-button appearance="plain">Skip</ha-progress-button>
<ha-progress-button variant="danger">Delete</ha-progress-button>
<ha-progress-button size="s">Check</ha-progress-button>
```

## Behavior

- **Resting**: looks and behaves like a regular button with the same appearance, variant, and size.
- **Progress**: the button switches to the accent appearance and shows a spinner instead of its label. It ignores pointer input, so people can't start the action twice.
- **Success**: the button turns to the success variant, and a white check mark covers the faded label, for two seconds.
- **Error**: the button turns to the danger variant, and a white alert icon covers the faded label, for two seconds.
- **Disabled**: like a disabled regular button.

The success and error states can only be triggered from code, so they are not shown here.

The hover, focus, and pressed states are those of the [button](https://contributors.home-assistant.io/design/components/button/#behavior).

## Specs

The sizes, spacing, and colors are those of the [button](https://contributors.home-assistant.io/design/components/button/#specs). On top of that:

| Property | Value | Token |
| --- | --- | --- |
| Appearance during progress and result | Accent | None |
| Variant on success | Success | `--ha-color-fill-success-loud-resting` |
| Variant on error | Danger | `--ha-color-fill-danger-loud-resting` |
| Result icon color | White | `--white-color` |
| Result icon size | 24px | None |
| Icon size in extra small and small | 16px | `--mdc-icon-size` |
| Result duration | 2 seconds | None |

## Guidelines

Do and don't, as live demos.

**Do:** Say what happens when you select the button.

```html
<ha-progress-button>Test connection</ha-progress-button>
```

**Don't:** Use a label that could mean anything.

```html
<ha-progress-button>OK</ha-progress-button>
```

- Keep labels short, and say what happens: **Save**, **Restart**, **Test connection**. See [UI text](https://contributors.home-assistant.io/design/ui-text/).
- When the action can fail with an error people need to read, show that error as well, for example in an [alert](https://contributors.home-assistant.io/design/components/alert/).

## Accessibility

### Keyboard

| Key | Action |
| --- | --- |
| <kbd>Tab</kbd> | Moves focus to the button, and away from it. A disabled button is skipped. |
| <kbd>Enter</kbd> or <kbd>Space</kbd> | Selects the button. Does nothing while it shows progress. |

### Target size

The same as the [button](https://contributors.home-assistant.io/design/components/button/#target-size): 40px high at the default size.

### Screen readers

The button is announced with its label, also while the result shows. During progress it is announced as busy. The success and error states only change the look: nothing is announced, so show an error people need to know about as text too.

### In the code

- The role is `button`, from the `<ha-button>` inside.
- While the result icon shows, the label is faded out instead of hidden, so the button keeps its accessible name.
- During progress, the inner button has `aria-busy="true"`.

## Related

- [Button](https://contributors.home-assistant.io/design/components/button/): the regular button this one wraps
- [Spinner](https://contributors.home-assistant.io/design/components/spinner/): progress on its own
- [Alert](https://contributors.home-assistant.io/design/components/alert/): showing an error people need to read

## In code

The element is `<ha-progress-button>`. It wraps `<ha-button>`. Set `progress` while the action runs, then call `actionSuccess()` or `actionError()` when it is done:

```html
<ha-progress-button>Restart</ha-progress-button>
```

```ts
private async _restart(ev) {
  const button = ev.currentTarget;
  button.progress = true;
  try {
    await doTheThing();
    button.actionSuccess();
  } catch (err) {
    button.actionError();
  } finally {
    button.progress = false;
  }
}
```

While `progress` is set, the button ignores pointer input, so people can't start the action twice.

### Attributes

- `progress`: shows the spinner. Reflected as an attribute.
- `disabled`: disables the button.
- `appearance`: `accent` (default), `filled`, `outlined`, or `plain`.
- `variant`: `brand` (default), `neutral`, `success`, `warning`, or `danger`.
- `size`: `xs`, `s`, `m` (default), `l`, or `xl`.
- `label`: the label, used when the default slot is empty.

These can only be set as properties:

- `iconPath`: SVG path data for an icon before the label.

### Slots

- Default: the label.

### Methods

- `actionSuccess()`: shows the success state for two seconds.
- `actionError()`: shows the error state for two seconds.

Source: [`src/components/buttons/ha-progress-button.ts`](https://github.com/home-assistant/frontend/blob/dev/src/components/buttons/ha-progress-button.ts)
