# Toggle (/ui/components/react/toggle)



<Playground component="toggle" />

## Usage [#usage]

```tsx
import { Toggle } from '@appica/ui-react/toggle'
import { Button } from '@appica/ui-react/button'
```

```tsx
<Toggle
  aria-label="Bold"
  render={
    <Button variant="outline" size="icon-md">
      B
    </Button>
  }
/>
```

`Toggle` is a behavior primitive — it renders a `<button aria-pressed>` and ships **no visual styling of its own**. To make it look like anything, compose it with our [`Button`](/ui/components/react/button) through `render={<Button …/>}` (or apply `buttonVariants({ variant, size })` as `className`). `Button` already reacts to the pressed state via `data-pressed`, so the pressed look comes for free.

Use it uncontrolled with `defaultPressed`, or controlled with `pressed` + `onPressedChange`. Every toggle needs an accessible name: give an icon-only toggle an `aria-label`, or use visible text children. To build a set of mutually-exclusive or multi-select toggles, group them in a [`ToggleGroup`](/ui/components/react/toggle-group), where each `Toggle` carries a `value`.

## Examples [#examples]

### Composing with Button [#composing-with-button]

A toolbar of icon toggles, each rendered as an `outline` `Button`. The pressed state is styled automatically through `data-pressed`; the first toggle starts on with `defaultPressed`.

```tsx
import { Button } from '@appica/ui-react/button'
import { Toggle } from '@appica/ui-react/toggle'
import { Bold, Italic, Underline } from '@appica/icons-react'

export default function ToggleWithButton() {
  return (
    <div className="flex items-center gap-2">
      <Toggle
        defaultPressed
        aria-label="Bold"
        render={
          <Button variant="outline" size="icon-md">
            <Bold />
          </Button>
        }
      />
      <Toggle
        aria-label="Italic"
        render={
          <Button variant="outline" size="icon-md">
            <Italic />
          </Button>
        }
      />
      <Toggle
        aria-label="Underline"
        render={
          <Button variant="outline" size="icon-md">
            <Underline />
          </Button>
        }
      />
    </div>
  )
}
```

### States [#states]

A toggle is off or on, and either state can also be `disabled`. `disabled` removes it from the tab order and exposes `data-disabled` for styling.

```tsx
import { Button } from '@appica/ui-react/button'
import { Toggle } from '@appica/ui-react/toggle'

export default function ToggleStates() {
  return (
    <div className="flex flex-wrap items-center gap-3">
      <Toggle
        aria-label="Off"
        render={
          <Button variant="outline" size="md">
            Off
          </Button>
        }
      />
      <Toggle
        defaultPressed
        aria-label="Pressed"
        render={
          <Button variant="outline" size="md">
            Pressed
          </Button>
        }
      />
      <Toggle
        disabled
        aria-label="Disabled"
        render={
          <Button variant="outline" size="md">
            Disabled
          </Button>
        }
      />
    </div>
  )
}
```

### Controlled [#controlled]

Hold the state yourself with `pressed` + `onPressedChange`, then derive the rest of the UI from it. Here a single boolean drives the whole row — the bell icon, the button's `variant`, the accessible label, and the helper text all follow the toggle's value.

```tsx
'use client'

import { useState } from 'react'
import { Button } from '@appica/ui-react/button'
import { Toggle } from '@appica/ui-react/toggle'
import { Bell, BellOff } from '@appica/icons-react'

export default function ToggleControlled() {
  const [enabled, setEnabled] = useState(true)
  return (
    <div className="flex w-full max-w-74 items-center justify-between gap-4 rounded-xl border p-4">
      <div className="flex flex-col gap-0.5">
        <span className="text-foreground-intense text-sm font-medium">Notifications</span>
        <span className="text-foreground-muted text-xs">
          {enabled ? "You'll be notified about new activity" : 'All notifications are paused'}
        </span>
      </div>
      <Toggle
        pressed={enabled}
        onPressedChange={setEnabled}
        aria-label={enabled ? 'Mute notifications' : 'Enable notifications'}
        render={
          <Button variant={enabled ? 'primary' : 'soft'} size="icon-md">
            {enabled ? <Bell /> : <BellOff />}
          </Button>
        }
      />
    </div>
  )
}
```

## RTL [#rtl]

Every Appica UI component supports right-to-left layouts out of the box. Set the `dir` attribute on a container (commonly your `<html>` element) so CSS logical properties resolve correctly, and wrap your tree in `DirectionProvider` so direction-aware behavior — roving focus, popup placement, and the like — follows the same direction.

```tsx
import { DirectionProvider } from '@appica/ui-react/providers/direction-provider'

export default function RootLayout({ children }) {
  return (
    <html lang="ar" dir="rtl">
      <body>
        <DirectionProvider dir="rtl">{children}</DirectionProvider>
      </body>
    </html>
  )
}
```

A row of toggles reorders from the start edge, following the resolved direction. For setup details and caveats, see the [RTL guide](/ui/docs/react/rtl).

<RtlPreview component="toggle" />

## API reference [#api-reference]

`Toggle` wraps [Base UI's Toggle](https://base-ui.com/react/components/toggle) and passes every remaining prop (`ref`, `aria-*`, and native `<button>` attributes) straight through. It exposes `data-pressed` and `data-disabled` state attributes for styling — see the Base UI docs for the full surface.

| Prop              | <ColMinWidth width="200">Type</ColMinWidth>                   | Default | <ColMinWidth width="220">Description</ColMinWidth>                                    |
| ----------------- | ------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------- |
| `pressed`         | `boolean`                                                     | —       | Controlled pressed state. Pair with `onPressedChange`.                                |
| `defaultPressed`  | `boolean`                                                     | `false` | Uncontrolled initial pressed state.                                                   |
| `onPressedChange` | <Code>(pressed: boolean, details) => void</Code>              | —       | Fires when the toggle is pressed or unpressed.                                        |
| `value`           | `string`                                                      | —       | Identity within a `ToggleGroup`; meaningless on a standalone toggle.                  |
| `disabled`        | `boolean`                                                     | `false` | Removes the toggle from the tab order and ignores interaction.                        |
| `nativeButton`    | `boolean`                                                     | `true`  | Whether the element passed to `render` is a native `<button>`.                        |
| `render`          | <Code>ReactElement \| ((props, state) => ReactElement)</Code> | —       | Replace the rendered element, or compose it with another component (e.g. `Button`).   |
| `className`       | <Code>string \| ((state) => string)</Code>                    | —       | Extra classes on the button, merged via `tailwind-merge`. May be a function of state. |
| `style`           | <Code>CSSProperties \| ((state) => CSSProperties)</Code>      | —       | Inline styles, optionally derived from state.                                         |

## Accessibility [#accessibility]

* Renders a `<button>` with `aria-pressed` reflecting the current state. **Space** (or **Enter**) toggles it; **Tab** moves focus to and from it.
* A toggle needs an accessible name — give an icon-only toggle an `aria-label`, or use visible text children.
* `disabled` removes the toggle from the tab order and exposes `data-disabled` for styling.
* The pressed state is exposed as both `aria-pressed` (for assistive tech) and `data-pressed` (for styling) — `Button` uses the latter to paint its pressed look.
