---
outline: deep
---

# Switch

Switches toggle a single setting on or off, taking effect immediately.

**`.l-switch`** — Native HTML Element

```html
<l-form-field>
  <label>Email notifications</label>
  <input
    type="checkbox"
    role="switch"
    checked
  />
</l-form-field>
```

A switch is a native `<input type="checkbox">` with `role="switch"` — keep the role so assistive tech announces "on/off" instead of "checked". [`l-form-field`](/elements/form-field) auto-styles a bare switch and wires the accessibility (label, hint, error, `aria-*`); standalone, apply `.l-switch` to the input yourself.

Use a switch for a setting that applies instantly (no Save step). For an option that only takes effect on form submission, prefer a [checkbox](/elements/checkbox).

## Options

### On

Native `checked` attribute.

### Disabled

Native `disabled` attribute.

### States

```html
<div class="flex flex-col gap-3">
  <l-form-field>
    <label>Off</label>
    <input
      type="checkbox"
      role="switch"
    />
  </l-form-field>
  <l-form-field>
    <label>On</label>
    <input
      type="checkbox"
      role="switch"
      checked
    />
  </l-form-field>
  <l-form-field>
    <label>Disabled</label>
    <input
      type="checkbox"
      role="switch"
      disabled
    />
  </l-form-field>
  <l-form-field>
    <label>Disabled on</label>
    <input
      type="checkbox"
      role="switch"
      checked
      disabled
    />
  </l-form-field>
  <l-form-field invalid>
    <label>Invalid (required, off)</label>
    <input
      type="checkbox"
      role="switch"
      required
    />
  </l-form-field>
</div>
```

### Invalid

Styled via `:user-invalid` (after interaction) or by setting `aria-invalid="true"`. Inside `l-form-field` this is managed for you.

### Size & accent

Override `--size` for the track height (the whole control scales from it) and `--accent` for the on fill.

```html
<div class="flex flex-col gap-3">
  <l-form-field>
    <label>Default</label>
    <input
      type="checkbox"
      role="switch"
      checked
    />
  </l-form-field>
  <l-form-field>
    <label>Large</label>
    <input
      type="checkbox"
      role="switch"
      class="[--size:1.5rem]"
      checked
    />
  </l-form-field>
  <l-form-field>
    <label>Extra large, dark accent</label>
    <input
      type="checkbox"
      role="switch"
      class="[--size:2rem] [--accent:var(--l-color-gray-900)]"
      checked
    />
  </l-form-field>
</div>
```

## Examples

### With a hint

`l-form-field` wires the accessibility (label, hint, `aria-*`).

```html
<l-form-field>
  <label>Email notifications</label>
  <input
    type="checkbox"
    role="switch"
    checked
  />
  <p class="l-hint">We'll only email you about account activity.</p>
</l-form-field>
```

### Right-to-left

In a `dir="rtl"` context the thumb rests at the inline-start (right) and slides to the inline-end (left) when on — no extra markup needed.

```html
<div dir="rtl">
  <l-form-field>
    <label>إشعارات البريد الإلكتروني</label>
    <input
      type="checkbox"
      role="switch"
      checked
    />
    <p class="l-hint">سنراسلك فقط بشأن نشاط حسابك.</p>
  </l-form-field>
</div>
```

## Accessibility

### Criteria

- **Role** — Native `<input type=checkbox>` plus `role=switch` — exposes the `switch` role with an on/off state
- **Accessible name** — Pair the switch with a `<label>` (wrap the input or use `for`/`id`)
- **State, not color** — On/off is conveyed by the thumb position and the `checked` state, not by color alone
- **Target size** — The label is part of the click target; keep the interactive area at least 24×24px
- **Focus visible** — Keyboard focus shows a 2px outline via `:focus-visible`
- **Reduced motion** — The slide and squish animations collapse to 0ms under `prefers-reduced-motion`
- **High contrast** — In forced-colors mode the track gains a system-color outline and the on state switches it to `Highlight`

### Rules

- Always add `role='switch'` to the `<input type='checkbox'>` — the skin and the inline field layout depend on it
- Always pair the switch with a `<label>` — wrap the input or link with `for`/`id`
- Use a switch only for settings that apply immediately; use a checkbox when the change is committed on submit
- Write the label as the thing being turned on (e.g. `Email notifications`), not an instruction

### Keyboard interactions

- `Tab` — Moves focus to the switch
- `Space` — Toggles the switch on or off

## API reference

### Importing

```css
@import 'luxen-ui/css/switch';
```

### Attributes & Properties

- **role** — Must be `switch`. Promotes the native checkbox to a switch for assistive tech and triggers the switch skin / inline field layout.
- **checked** — Whether the switch is on.
- **disabled** — Disables the switch.
- **required** — Marks the switch as required for form submission.
- **aria-invalid** — Set to `true` to force the invalid style (otherwise applied via `:user-invalid`). `l-form-field` manages this automatically.

### CSS classes

- `.l-switch` — Base switch style, applied to `<input type="checkbox" role="switch">`. The `role="switch"` is required so assistive tech announces "on/off" (not "checked") and `l-form-field` lays it out inline. Inside `l-form-field` a bare switch is auto-styled, so the class is optional there.

### CSS custom properties

- `--size` (default: `1.25em`) — Track height; the whole control scales from it.
- `--accent` (default: `var(--l-form-control-activated-color)`) — Track fill when on.
