# Switch Guides

## Patterns

### Immediate Settings Toggle

When to use:

- One preference or feature should turn on or off directly.

Composition notes:

- Keep the visible label state-oriented.
- Give `SwitchInput` a `name` if the setting also lives in a native form.

Trade-offs:

- Strong binary affordance.
- Weak fit for groups of mutually exclusive options.

```tsx
import { useState } from 'react';
import { Label, Switch, SwitchIndicator, SwitchInput, Text } from '@vega-ui/react';

export default function ParentOwnedSwitchState() {
  const [maintenance, setMaintenance] = useState(false);

  return (
    <div style={{ display: 'grid', gap: 'var(--spacing-6)', width: '100%', maxWidth: 420 }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 'var(--spacing-8)' }}>
        <Label htmlFor='maintenance-mode'>Maintenance mode</Label>
        <Switch>
          <SwitchInput
            id='maintenance-mode'
            checked={maintenance}
            onChange={(event) => setMaintenance(event.currentTarget.checked)}
          />
          <SwitchIndicator />
        </Switch>
      </div>
      <Text size={2} aria-live='polite' style={{ color: 'var(--label-secondary)' }}>
        {maintenance ? 'Visitors see the maintenance page. Admins can still sign in.' : 'The site is live for everyone.'}
      </Text>
    </div>
  );
}
```

### Settings Row With Helper Text

When to use:

- A settings screen needs a compact toggle plus short explanatory copy.

Composition notes:

- Keep the switch and primary label on one row.
- Put optional helper text below instead of inside the label itself.

Trade-offs:

- Easy to scan in preferences panels.
- Can become noisy if every row adds too much helper copy.

```tsx
import { Label, Switch, SwitchIndicator, SwitchInput, Text } from '@vega-ui/react';

const settings = [
  { id: 'auto-updates', title: 'Automatic updates', description: 'Install security patches overnight.', checked: true },
  { id: 'usage-data', title: 'Share usage data', description: 'Help us improve with anonymous diagnostics.', checked: false },
  { id: 'beta-features', title: 'Beta features', description: 'Try new tools before they are released.', checked: false },
];

export default function SettingsToggle() {
  return (
    <div style={{ display: 'grid', gap: 'var(--spacing-8)', width: '100%' }}>
      {settings.map((setting) => (
        <div key={setting.id} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 'var(--spacing-8)' }}>
          <div style={{ display: 'grid', gap: 'var(--spacing-1)' }}>
            <Label htmlFor={setting.id}>{setting.title}</Label>
            <Text id={`${setting.id}-description`} size={2} style={{ color: 'var(--label-secondary)' }}>
              {setting.description}
            </Text>
          </div>
          <Switch style={{ flexShrink: 0 }}>
            <SwitchInput id={setting.id} defaultChecked={setting.checked} aria-describedby={`${setting.id}-description`} />
            <SwitchIndicator />
          </Switch>
        </div>
      ))}
    </div>
  );
}
```

### Overlay Toggle List

When to use:

- A drawer or sheet contains a short list of binary settings.

Composition notes:

- Keep the list short and clearly state-oriented.
- Avoid mixing toggles with mutually exclusive choice patterns in the same visual cluster.

Trade-offs:

- Works well for compact preference panels.
- Harder to scan if too many switches are stacked with weak labels.

```tsx
import { CSSProperties } from 'react';
import {
  Button,
  Heading,
  Icon,
  IconButton,
  Label,
  Sheet,
  SheetClose,
  SheetContent,
  SheetHandle,
  SheetTrigger,
  Switch,
  SwitchIndicator,
  SwitchInput,
} from '@vega-ui/react';
import { XIcon } from '@vega-ui/icons';

const options = [
  { id: 'sheet-autoplay', title: 'Autoplay next episode', checked: true },
  { id: 'sheet-subtitles', title: 'Always show subtitles', checked: false },
  { id: 'sheet-data-saver', title: 'Data saver on mobile networks', checked: true },
];

export default function OverlayToggleList() {
  return (
    <Sheet>
      <SheetTrigger asChild>
        <Button>Playback settings</Button>
      </SheetTrigger>
      <SheetContent aria-labelledby='playback-settings-title'>
        <SheetHandle aria-label='Resize sheet' />
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 'var(--spacing-8)' }}>
          <Heading id='playback-settings-title' size={4} fontWeight={600} as='h2'>Playback settings</Heading>
          <SheetClose asChild>
            <IconButton
              aria-label='Close'
              variant='secondary'
              appearance='ghost'
              style={{ flexShrink: 0, '--icon-button-size': '24px', '--icon-button-br-ratio': 0.5 } as CSSProperties}
            >
              <Icon size='xs'><XIcon strokeWidth={2.5} /></Icon>
            </IconButton>
          </SheetClose>
        </div>
        <div style={{ display: 'grid', gap: 'var(--spacing-8)' }}>
          {options.map((option) => (
            <div key={option.id} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 'var(--spacing-8)' }}>
              <Label htmlFor={option.id}>{option.title}</Label>
              <Switch style={{ flexShrink: 0 }}>
                <SwitchInput id={option.id} name={option.id} defaultChecked={option.checked} />
                <SwitchIndicator />
              </Switch>
            </div>
          ))}
        </div>
      </SheetContent>
    </Sheet>
  );
}
```

## Comparison

### Quick Decision Rule

Use `Switch` for one immediate binary setting.

### `Switch` vs `Checkbox`

Use `Switch` when:

- the control represents one immediate on/off setting

Use `Checkbox` when:

- the control represents an independent selectable option in a form or list

Main trade-off: switches read as immediate state changes, while checkboxes read as selection.

### `Switch` vs `Radio`

Use `Switch` when:

- only one binary setting is involved

Use `Radio` when:

- the user must choose one option from a set

Main trade-off: switches toggle one setting; radios compare alternatives.

### `Switch` vs `SegmentedControl`

Use `Switch` when:

- the choice is binary and immediate

Use `SegmentedControl` when:

- several always-visible exclusive options should be compared side by side

Main trade-off: switch is a binary toggle; segmented control is an exclusive option selector.

### `Switch` vs `CheckboxCard`

Use `Switch` when:

- one binary feature should turn on or off immediately

Use `CheckboxCard` when:

- multiple rich options can be selected independently and the UI should read as option tiles

### Choose This Component When

- The feature is one immediate binary setting.
- The label describes a feature that is on or off.
- The UI should read as a toggle, not a form choice group.
- users should not have to compare several visible alternatives first

### Do Not Choose This Component When

- The user is choosing one option from several.
- Multiple independent options appear in a list.
- The state should feel like a deferred form choice instead of an immediate setting.

## Troubleshooting

### Switch Looks Right But Does Not Submit

#### Symptom

The toggle changes visually, but the value never appears in native form submission.

#### Likely Cause

`SwitchInput` was omitted.

#### How To Verify

- Inspect the rendered markup.
- Submit the form and check whether the switch value is present.

#### Fix

- Render `SwitchInput` inside the switch root.

### Label Reads Like An Action Instead Of A State

#### Symptom

Users cannot tell whether the switch controls a feature state or an action.

#### Likely Cause

The visible text was written as "Turn on" or "Enable now" instead of naming the setting.

#### How To Verify

- Read the label without seeing the current checked state.
- Check whether the feature meaning is still obvious.

#### Fix

- Rewrite the label to describe the controlled setting, such as "Incident alerts".

### Switch Was Used For The Wrong Product Model

#### Symptom

The UI technically works, but it feels wrong because the choice is really exclusive or multi-select.

#### Likely Cause

`Switch` was chosen for a selection model better served by `Radio`, `Checkbox`, or `SegmentedControl`.

#### How To Verify

- Check whether the setting is binary, exclusive, or independently selectable.
- Compare the surrounding flow with the intended choice model.

#### Fix

- Use `Radio` for exclusive choice sets.
- Use `Checkbox` for independent selectable options.
- Use `SegmentedControl` for always-visible exclusive options.
