# Switch

> An iOS-style switch with squash and stretch: the thumb stretches toward where it is going on touch down, then travels on a spring while the track color follows. Settings-row layout, tones, sizes and optimistic async changes.

- Type: Component (inputs)
- Access: Free, open source (MIT)
- Page: https://goodui.dev/native/components/switch
- Markdown: https://goodui.dev/native/components/switch.md
- Registry item: https://goodui.dev/native/r/switch.json
- Dependencies: react-native-reanimated
- Keywords: react native switch, toggle switch, ios toggle, settings toggle row, animated switch, async toggle

## When to use

- On or off settings that take effect immediately: notifications, dark mode, Face ID.
- Settings saved to a server: return the promise from onValueChange.
- A settings list: pass label and description for the full row.

## When not to use

- Choices submitted later with a form, or several options in a list: use checkbox.
- One of two named views: use segmented-control.
- A destructive change: use hold-to-confirm.

## Installation

With the shadcn CLI (needs a components.json in the Expo app), then `npx expo install --fix` so native dependencies match your Expo SDK. The foundation comes along the first time.

```bash
npx shadcn@latest add https://goodui.dev/native/r/switch.json
npx expo install --fix
```

The component lands in `components/goodui-native/switch/` and imports the foundation from `components/goodui-native/foundation/` with relative paths; it also installs locale.

Built-in strings follow `<GooduiLocaleProvider>` (one [language pack](https://goodui.dev/native/r/locale-tr.json) translates the whole kit); the `labels` prop overrides them for one instance.

## Usage

```tsx
import { useState } from "react";
import { Switch } from "@/components/goodui-native/switch/switch";

export function PushSetting() {
  const [push, setPush] = useState(true);
  return (
    <Switch
      label="Push notifications"
      description="Bookings, reminders and messages"
      value={push}
      onValueChange={async (next) => {
        await api.saveSettings({ push: next });
        setPush(next);
      }}
    />
  );
}
```

## Examples

### Inline with a screen reader label

```tsx
<Switch accessibilityLabel="Round-up savings" defaultValue tone="success" />
```

### Small

```tsx
<Switch size="sm" accessibilityLabel="Show weekends" value={weekends} onValueChange={setWeekends} />
```

## API reference

### Switch

`import { Switch } from "@/components/goodui-native/switch/switch";`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `boolean` | – | On or off (controlled). Pair it with `onValueChange`. |
| `defaultValue` | `boolean` | `false` | Initial state when uncontrolled. |
| `onValueChange` | `(value: boolean) => unknown` | – | Called with the new state. Return a promise (for example a settings request) and the switch flips right away, shows a spinner in the thumb while pending, and flips back with an error haptic and a shake if it rejects. |
| `tone` | `"success" \| "warning" \| "danger" \| "accent"` | `"accent"` | Track color when on. `accent` by default; `success`, `warning` and `danger` only when the setting means that status. |
| `size` | `"sm" \| "md"` | `"md"` | 40 × 24 (`sm`) or 51 × 31 pt (`md`, the iOS size). The touch target stays 44 pt. |
| `label` | `string` | – | Turns it into a settings row: the label on the leading side, the switch trailing, the whole row toggles. |
| `description` | `string` | – | Secondary line under the row label. |
| `disabled` | `boolean` | `false` | Dims the control and ignores presses. |
| `haptic` | `boolean` | `true` | `false` silences the select haptic on change. |
| `accessibilityLabel` | `string` | – | Screen reader label when there is no visible `label`. |
| `accessibilityHint` | `string` | – | Describes what happens on activation, read after the label. |
| `labels` | `Partial<SwitchLabels>` | – | Overrides for the built-in strings; a GooduiLocaleProvider pack sets them app-wide. |
| `style` | `StyleProp<ViewStyle>` | – | Style for the outer container. |
| `testID` | `string` | – | Identifier for end-to-end tests. |

## Accessibility

- accessibilityRole is switch with checked, disabled and busy (while a returned promise is pending) in accessibilityState.
- In the row layout the whole row is the switch, labelled 'label, description'. Inline, pass accessibilityLabel.
- A rejected change is announced ('Couldn't change the setting').
- The inline switch has hitSlop up to a 44 pt target; the row is at least 44 pt tall.

## Motion

- Press: the thumb widens toward the far side and squashes to 92 % height on the snappy spring, from touch down.
- Change: the thumb travels on the snappy spring and the track color interpolates with it.
- Pending: a spinner turns inside the thumb. Rejected: the switch flips back and shakes.
- Reduced motion: no squash, stretch or shake; the thumb moves with a short timing.

## Haptics

- toggle-on or toggle-off on change
- error when a returned promise rejects

## Performance

- Thumb geometry and colors animate on the UI thread; a toggle is one React update.

## Notes for AI

- Controlled (value + onValueChange) or uncontrolled (defaultValue).
- Return a promise from onValueChange to get optimistic flipping, a pending spinner and automatic revert on failure. Do not add your own loading state.
- Use label and description instead of building your own row around it.
- Use tone only when the setting means a status; the default accent is right for almost everything.

## Related

- [Checkbox and radio](https://goodui.dev/native/components/checkbox.md): Checkboxes whose check draws itself in (an indeterminate dash retracts into it) and radios whose dot pops into the center, inline or as list rows, with CheckboxGroup and RadioGroup helpers.
- [Segmented control](https://goodui.dev/native/components/segmented-control.md): Two to five views of the same thing with an elastic highlight that stretches toward the new segment, can be dragged, and ticks at every boundary. Includes a billing toggle.
- [Hold to confirm](https://goodui.dev/native/components/hold-to-confirm.md): Confirms an irreversible action by holding: ink fills from the leading edge, the label inverts where the ink passes, and haptics tick at every quarter.

## Guidance for AI tools

Switch: An iOS-style switch with squash and stretch: the thumb stretches toward where it is going on touch down, then travels on a spring while the track color follows. Settings-row layout, tones, sizes and optimistic async changes. Use only the documented props. Keep accessibility, reduced motion and both color schemes intact when adapting it.

Full library index: https://goodui.dev/native/llms.txt
