# Button

> An action, pressed: one that can stay in reach while unavailable and say why, show its work, or toggle.

A button does something when pressed: submits a form, opens a dialog, starts a
task. A button that toggles is on or off, and says which.

## When to use

Use a button for an action. To go somewhere, use a link; to choose one of a few
values, use a [radio group](https://ui.publictheta.com/components/radio-group.md); for a setting that is on
or off as part of a form, a [checkbox](https://ui.publictheta.com/components/checkbox.md).

## Why it is a component

A button's looks could be a class on the platform's own `<button>`, and for a
long time that is all this library had. What a class cannot give is behaviour a
plain button lacks, and every interface needs:

- **Disabled, but in reach.** A disabled button leaves the Tab order and cannot
  say why. One that is merely unavailable for now — Save before anything has
  changed — can stay reachable, be announced as unavailable, and carry its
  reason.
- **Pending.** A button whose work is under way ignores further presses, so the
  work is not started twice, while keeping focus and its name. Disabling it
  instead would throw focus to the page.
- **On and off.** A toggle states whether it is pressed, and turns on and off
  with each press, held by its owner or by itself.
- **A name.** A button that shows only a mark is reported while developing when
  it has no name.

These hold for every button, which is why they live in one place.

## Best practices

**Say what it does.** A verb, or a verb and its object: Save, Remove file. A
button that opens a dialog ends with an ellipsis, Remove…, because it asks
before it acts.

**One primary button per task.** The button a task ends with is primary;
another that destroys something is a danger button, and is never the default.

**Keep in reach what will become available.** A button that is unavailable for
a reason the person can change — fill in a field, make a change — stays
focusable and says the reason. One that does not apply at all is disabled, or
not shown.

**Show work in progress on the button that started it.** It keeps its width and
its label for assistive technology, shows that it is busy, and ignores presses
until the work is done.

**Name a button that shows only a mark.** In words, in the language of the
interface.

## Platform considerations

**Keyboard.** Enter and Space press it. A button that is unavailable or busy
hears them and does nothing. WebKit on macOS leaves buttons out of the Tab order
unless the person has asked for every control; that is the person's setting, and
a button keeps it.

**Pointer.** It shows the pointer over it, and the press while it is held. A
button that cannot be pressed shows neither.

**Touch.** A finger cannot hover, so a tap leaves no hover behind: the button is
drawn as at rest once the finger lifts. Every size can be hit 44 CSS pixels
across; a small one by a target that reaches past its drawn edge.

**Forced colours.** A system that forces its own colours draws a disabled
button in its colour for what is unavailable, and a toggle that is on in its
highlight. A button that is only marked unavailable is drawn the same way, since
the system does not know of it.

**Assistive technology.** It is a button, named by its label; a toggle states
whether it is pressed; one in reach but unavailable is announced as unavailable,
with its reason as its description; one at work is busy.

## Behaviour

Each statement is verified by a test in Chromium, Chromium (touch), Firefox, WebKit, WebKit (touch), unless it names the environments it applies to or is marked open.

### Semantics

- Is a button named by its label.
- Does not submit a form unless it is asked to.
- Has no accessibility violations in any variant, size or state.

### Toggle

- A button that toggles states whether it is on, and a press turns it on and off.
- One that does not toggle says nothing of being on.
- One that is on looks it, in any variant, also where the system forces its colours.

### Disabled

- Disabled, it cannot be pressed or focused.
- Kept in reach, it can be focused and is announced as disabled, but does nothing when pressed.
- Kept in reach, it does not submit its form, by a press or by Return in a field.
- Given a reason, it stays in reach and the reason is its description.
- A reason is not said once it is no longer disabled.
- Kept in reach, becoming disabled leaves focus where it was.
- Kept in reach, it does not answer the pointer as one that can be pressed. *(Chromium, Firefox, WebKit)*
- Unavailable, it looks unavailable whatever its variant.
- Kept in reach, it is drawn in the system's colour for what is unavailable where colours are forced.

### Pending

- Pending, it says it is busy and ignores presses, keeping its name.
- Becoming pending leaves focus on it, and its width as it was.
- Pending, it does not submit its form.

### Pointer

- Under a mouse it shows the pointer over it, and the press while it is held. *(Chromium, Firefox, WebKit)*
- Under a finger a tap leaves no hover behind: it is drawn as at rest. *(Chromium (touch), WebKit (touch))*
- Under a finger every size can be hit 44 pixels across, a small one beyond its edge. *(Chromium (touch), WebKit (touch))*

### Naming

- One that shows only a mark and has no name is reported while developing.

## Reference implementation

React: `npx shadcn@latest add https://ui.publictheta.com/r/button.json`
