# Switch

> A toggle for binary settings that take effect immediately. Behaves like a checkbox under the hood, styled as a pill.

- Category: form
- Status: stable (since 1.0.0)
- A11y pattern: https://www.w3.org/WAI/ARIA/apg/patterns/switch/
- Tokens: --cta-background, --cta-foreground, --foreground-primary, --foreground-secondary, --background-secondary
- Playground: https://design.freecodecamp.org/playground#switch
- npm dependencies: `react@>=18 <20`
- Registry dependencies: [theme](https://design.freecodecamp.org/registry/theme.md)
- Files:
  - `Switch.tsx` → `src/ui/switch/Switch.tsx` (raw: https://design.freecodecamp.org/registry/switch/Switch.tsx)
  - `switch.css` → `src/ui/switch/switch.css` (raw: https://design.freecodecamp.org/registry/switch/switch.css)

## Install (copy source)

1. Ensure the theme is installed once per project - tokens.css + base.css imported globally, fonts available. See https://design.freecodecamp.org/registry/theme.md and https://design.freecodecamp.org/registry/starter.md.
2. Copy the files below into `src/ui/switch/` (adjust to your project layout) and import the CSS once from your global stylesheet, e.g. `@import './ui/switch/switch.css';`.
3. Colors, spacing and type come from tokens - tailor the component by editing the copied source; recolour by editing tokens.css, not the component CSS.

## Usage

`<Switch>` is the pill-shaped toggle for binary settings that apply
immediately - dark mode, notifications, autoplay. The underlying input is
a native checkbox, so it participates in HTML forms just like Checkbox.

## Usage

```tsx
import { Switch } from './ui/switch/Switch';
<Switch name='emails' label='Email me weekly digests' defaultChecked />;
```

## Keyboard

| Key   | Action             |
| ----- | ------------------ |
| Space | Toggles the switch |
| Tab   | Moves focus        |

## Accessibility

Switches announce as "switch, on" / "switch, off" in screen readers on
platforms that map the WAI-ARIA `switch` pattern natively. Use Switch
only when the change takes effect immediately - if the user has to hit
"Save" afterwards, Checkbox is the right primitive.

## Example

```tsx
import { Switch } from './ui/switch/Switch';

<Switch defaultChecked label="Keyboard shortcuts" />
<Switch label="Sound effects" />
```

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `label` | `ReactNode` | no | - |  |
| `labelClassName` | `string` | no | `` |  |

## Source: Switch.tsx

```tsx
import React, { forwardRef } from 'react';

export interface SwitchProps extends Omit<
  React.InputHTMLAttributes<HTMLInputElement>,
  'type'
> {
  label?: React.ReactNode;
  labelClassName?: string;
}

export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
  ({ label, labelClassName = '', className = '', id, ...rest }, ref) => {
    const classes = ['switch', labelClassName].filter(Boolean).join(' ');
    return (
      <label className={classes} htmlFor={id}>
        <input
          ref={ref}
          type='checkbox'
          id={id}
          className={className}
          {...rest}
        />
        <span className='switch__track'>
          <span className='switch__thumb' />
        </span>
        {label !== undefined && <span className='switch__label'>{label}</span>}
      </label>
    );
  }
);
Switch.displayName = 'Switch';
```

## Source: switch.css

```css
.switch {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  user-select: none;
}
.switch input {
  position: absolute;
  width: 0;
  height: 0;
  opacity: 0;
}
.switch__track {
  position: relative;
  width: 40px;
  height: 20px;
  background: var(--background-quaternary);
  transition: background-color 120ms;
}
.switch__thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  background: var(--foreground-primary);
  transition: left 120ms;
}
.switch input:checked + .switch__track {
  background: var(--cta-background);
}
.switch input:checked + .switch__track .switch__thumb {
  left: 22px;
  background: var(--cta-foreground);
}
.switch input:disabled + .switch__track {
  opacity: 0.5;
}
.switch__label {
  font-size: var(--fs-md);
  color: var(--foreground-primary);
}
```

## HTML / vanilla variant

```html
<label class="switch">
  <input type="checkbox" checked />
  <span class="switch__track"><span class="switch__thumb"></span></span>
  <span class="switch__label">Keyboard shortcuts</span>
</label>
```

Interactive behaviours for plain HTML come from the vanilla runtime (data-uikit-* attributes): https://design.freecodecamp.org/registry/vanilla.md - or download https://design.freecodecamp.org/cdn/uikit.global.js once and self-host it (do not hotlink).

## For coding agents

This library is distributed as copyable source, not an npm package. Start at https://design.freecodecamp.org/registry/starter.md, discover components via https://design.freecodecamp.org/llms.txt, and copy files into the consuming project. Keep token names intact; recolour by editing the copied tokens.css.
