# Switch

_Box Kite 2.2.6 · a markdown copy of https://www.box-kite.dev/switch/_

An on/off control. A real checkbox input underneath, wearing role=switch — so a screen reader says on and off, and a form still submits it.

**Import**

```jsx
import Switch from '@box-kite/react/components/switch';
```

**Usage**

```jsx
<Switch name="notify" label="Email notifications" defaultChecked />
```

## Why it is still an input

A switch drawn from a `<div>` has to reimplement focus, Space, the disabled state and the tab order — and it submits nothing. This one is the same `<input type="checkbox">` a `Checkbox` renders, with `role="switch"` over it, so all of that comes from the platform. The role is the whole difference to a screen reader: "on"/"off" rather than "checked"/"not checked".

The track and the thumb are one element and its `::before`. Nothing decorative is in the accessibility tree, and there is no second element to keep in sync with the first.

**Controlled**

```jsx
const [notify, setNotify] = useState(true);

<Switch name="notify" label="Email notifications" checked={notify} onChange={(e) => setNotify(e.target.checked)} />
```

## Styling

Box props on `<Switch>` style the track, on top of the built-in `switch` component style; `labelProps` styles the `<label>` around the pair. `checked` is both the state and the styles for it — the tuple form takes the value first and what `:checked` should look like second, so recolouring the on state does not need a second prop or a class of your own.

```jsx
<Switch
  name="notify"
  label="Email notifications"
  checked={[on, { bgColor: 'emerald-500' }]}
  onChange={(e) => setOn(e.target.checked)}
  labelProps={{ gap: 3, fontSize: 14 }}
/>
```

Emerald

## Switch props

Everything below is this component’s own. All 235 of Box’s style props work on it too, and those are on [/box](https://www.box-kite.dev/box.md) rather than repeated here.

| Prop | Type | Default | What it does |
| --- | --- | --- | --- |
| `name` | `string` | — | What the switch submits under. Needed for a form; a controlled switch can do without one. |
| `props` | `OmitTagProps<BoxTagProps<'input'>, 'type'>` | — | Attributes for the `<input>` itself. `type` is the component's, and `role` is already `switch`. |
| `onInput` | `(e: React.ChangeEvent<HTMLInputElement>) => void` | — | Fires on every keystroke or click. On a checkbox this is the same moment as `onChange`. |
| `onChange` | `(e: React.ChangeEvent<HTMLInputElement>) => void` | — | Fires when the switch is toggled. `e.target.checked` is the new state. |
| `value` | `string \| number` | — | The value the form submits when it is on. Defaults to `"on"`, as HTML does. |
| `autoFocus` | `boolean` | — | Focus it on mount. One per page at most — a stolen focus is a lost place in the document. |
| `readOnly` | `boolean` | — | Rendered and read, but not toggleable. Unlike `disabled` it stays in the tab order and submits. |
| `defaultChecked` | `boolean` | — | The state it starts in when the switch is uncontrolled. Pass `checked` instead to control it. |
| `label` | `React.ReactNode` | — | The text beside the switch, rendered inside a label that wraps the input. |
| `labelProps` | `BoxProps<'label'>` | — | Styles for the wrapping `<label>`: the row's layout, not the track's own appearance. |

## Switch keyboard

| Key | Result |
| --- | --- |
| `Tab` | Focuses the switch. It is one tab stop, like any other control. |
| `Space` | Toggles it. The platform supplies this one. |
| `Enter` | Toggles it too, and does not submit the surrounding form. APG lists Enter as optional, and a bare checkbox ignores it. |

## Switch accessibility

Implements [the WAI-ARIA APG pattern](https://www.w3.org/WAI/ARIA/apg/patterns/switch/).

- A real `<input type="checkbox">` under `role="switch"`, so focus, the disabled state and form submission are the platform's rather than this component's.
- `aria-checked` is the input's own checked state — there is no second element to keep in step with it, and no mixed state to get wrong.
- `label` renders the `<label>` wrapping the input, which is what names it. The track and the thumb are one element and its `::before`, so nothing decorative reaches the accessibility tree.

Swept with axe on every release, in this state: `Switch`. No violations, with contrast and landmark rules left to a human. Screen-reader results are not published yet.

## Switch style tree

Every part the component draws is a node with a name, so a default can be restyled with `Box.components()` instead of a selector — and a variant is a name too.

`switch`

---

_Every page: https://www.box-kite.dev/llms.txt · every prop, measured: https://www.box-kite.dev/props.md_

