# Toggle

A button with two states that stays pressed until the next click.

```tsx
import { Toggle } from 'ferry-ui'
import { Archive, Pin } from 'lucide-react'

export default function ToggleHero() {
  return (
    <>
      <Toggle variant="outline" defaultPressed>
        <Pin /> Pinned first
      </Toggle>
      <Toggle variant="outline">
        <Archive /> Archived
      </Toggle>
    </>
  )
}
```

## Usage guidelines

- **A state, not an action.** A toggle stays pressed. For an action that runs one time, use [Button](/docs/components/button).
- **A view option, not a setting.** Use a toggle in a toolbar. For a setting that applies immediately, use [Switch](/docs/components/switch).
- **One toggle, one option.** To pick one option of a set, use [Toggle Group](/docs/components/toggle-group) or [Tabs](/docs/components/tabs).

## Anatomy

Import the component. A toggle has one part.

```tsx title="Anatomy"

<Toggle />
```

## Examples

### Variants

The `variant` prop sets the look. A pressed toggle changes its fill.

```tsx
import { Toggle } from 'ferry-ui'
import { Star } from 'lucide-react'

export default function ToggleVariants() {
  return (
    <>
      <Toggle>
        <Star /> Default
      </Toggle>
      <Toggle defaultPressed>
        <Star /> Default, pressed
      </Toggle>
      <Toggle variant="outline">
        <Star /> Outline
      </Toggle>
      <Toggle variant="outline" defaultPressed>
        <Star /> Outline, pressed
      </Toggle>
    </>
  )
}
```

| Variant | Look | Use |
| --- | --- | --- |
| `default` | No border and no fill. | A toggle in a toolbar. |
| `outline` | A border and a fill. | A toggle that stands alone near other controls. |

### Sizes

The `size` prop sets the height. A toggle has the same height as a `Button` of the same size.

```tsx
import { Toggle } from 'ferry-ui'

export default function ToggleSizes() {
  return (
    <>
      <Toggle variant="outline" size="tiny">
        Tiny, 26px
      </Toggle>
      <Toggle variant="outline" size="sm">
        Small, 30px
      </Toggle>
      <Toggle variant="outline" size="md">
        Medium, 34px
      </Toggle>
    </>
  )
}
```

| Size | Height |
| --- | --- |
| `tiny` | 26px |
| `sm` | 30px (default) |
| `md` | 34px |

The sizes `default` and `lg` are deprecated names of `sm` and `md`. Do not use them.

### Icon only

A toggle with only an icon must have an `aria-label`. For a tooltip, wrap the toggle in [`Hint`](/docs/components/tooltip).

```tsx
import { Hint, Toggle } from 'ferry-ui'
import { Bold, Italic, Underline } from 'lucide-react'

export default function ToggleIconOnly() {
  return (
    <div role="group" aria-label="Text format" className="flex items-center gap-0.5">
      <Hint label="Bold">
        <Toggle aria-label="Bold" defaultPressed>
          <Bold />
        </Toggle>
      </Hint>
      <Hint label="Italic">
        <Toggle aria-label="Italic">
          <Italic />
        </Toggle>
      </Hint>
      <Hint label="Underline">
        <Toggle aria-label="Underline">
          <Underline />
        </Toggle>
      </Hint>
    </div>
  )
}
```

### Disabled state

Set `disabled` to refuse clicks. The toggle keeps its state.

```tsx
import { Toggle } from 'ferry-ui'
import { Pin } from 'lucide-react'

export default function ToggleDisabled() {
  return (
    <>
      <Toggle variant="outline" disabled>
        <Pin /> Pinned first
      </Toggle>
      <Toggle variant="outline" disabled defaultPressed>
        <Pin /> Pinned first
      </Toggle>
    </>
  )
}
```

### Controlled state

A toggle holds its state by default. Use `defaultPressed` to press it at the start.

To control the state, pass `pressed` and `onPressedChange`. Use this when the state changes other content.

```tsx
import * as React from 'react'
import { Badge, Toggle } from 'ferry-ui'
import { Archive } from 'lucide-react'

const PROJECTS = [
  { name: 'Customer portal', archived: false },
  { name: 'Marketing site', archived: false },
  { name: 'Old intranet', archived: true },
]

export default function ToggleControlled() {
  const [showArchived, setShowArchived] = React.useState(false)
  const projects = PROJECTS.filter((project) => showArchived || !project.archived)

  return (
    <div className="flex w-full max-w-sm flex-col gap-3">
      <Toggle variant="outline" className="w-fit" pressed={showArchived} onPressedChange={setShowArchived}>
        <Archive /> Archived
      </Toggle>
      <ul aria-label="Projects" className="divide-y rounded-lg border bg-surface-100 text-[13px] text-foreground">
        {projects.map((project) => (
          <li key={project.name} className="flex items-center justify-between px-4 py-2.5">
            {project.name}
            {project.archived && <Badge>Archived</Badge>}
          </li>
        ))}
      </ul>
    </div>
  )
}
```

## Accessibility

- A toggle is a button with the `aria-pressed` attribute. A screen reader reads the pressed state.
- A tooltip is not an accessible name. An icon-only toggle must have an `aria-label`.

## API reference

`Toggle` also accepts the props of its Radix UI primitive and each attribute of the `<button>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `"default" \| "outline"` | `default` | `default` = transparent until hovered/pressed; `outline` = bordered control on surface-100. |
| `size` | `"default" \| "tiny" \| "sm" \| "md" \| "lg"` | `sm` | Height, on the `Button` scale: `tiny` 26px, `sm` 30px (default), `md` 34px. `default` and `lg` are deprecated aliases of `sm` and `md`. |
| `pressed` | `boolean` |  | The controlled state of the toggle. |
| `defaultPressed` | `boolean` | `false` | The state of the toggle when initially rendered. Use `defaultPressed` if you do not need to control the state of the toggle. |
| `onPressedChange` | `((pressed: boolean) => void)` |  | The callback that fires when the state of the toggle changes. |
| `asChild` | `boolean` |  |  |

### toggleVariants

`toggleVariants({ variant, size })` returns the classes of a toggle. Use it to give the toggle look to an element that is not a `Toggle`.

| Option | Type | Role |
| --- | --- | --- |
| `variant` | `'default'` or `'outline'` | The look. The default is `default`. |
| `size` | `'tiny'`, `'sm'` or `'md'` | The height. The default is `sm`. |
