# Toggle Family

> Toggle Family: anatomy, keyboard behavior, state, and theming in Askr.

Source: [https://askrjs.com/docs/components/toggle-family](https://askrjs.com/docs/components/toggle-family)

Status: stable. Packages: @askrjs/ui/toggle, @askrjs/ui/toggle-group, @askrjs/themes/toggle, @askrjs/themes/toggle-group.

**Published packages are authoritative.** Examples may lag behind a published contract. When guidance differs, verify the exports and TypeScript declarations in your installed package, then file an issue.

## Example

```tsx
import { Toggle, ToggleGroup, ToggleGroupItem } from '@askrjs/themes/components';

<>
  <Toggle pressed={bold()} onPress={() => setBold((value) => !value)}>Bold</Toggle>
  <ToggleGroup type="single" value={alignment()} onValueChange={setAlignment}>
    <ToggleGroupItem value="left">Left</ToggleGroupItem>
    <ToggleGroupItem value="center">Center</ToggleGroupItem>
  </ToggleGroup>
</>
```

## Published props

Generated from the TypeScript declarations shipped by the installed package.

### `ToggleAsChildProps`

Import from `@askrjs/ui/toggle`.

- `asChild: true;`
- `children: JSXElement;`
- `disabled?: boolean | undefined;`
- `onPress?: ((e: PressEvent) => void) | undefined;`
- `pressed?: boolean | undefined;`
- `ref?: Ref<Element>;`
- `type?: undefined;`

### `ToggleButtonProps`

Import from `@askrjs/ui/toggle`.

- `asChild?: false | undefined;`
- `children?: unknown;`
- `disabled?: boolean | undefined;`
- `onPress?: ((e: PressEvent) => void) | undefined;`
- `pressed?: boolean | undefined;`
- `ref?: Ref<HTMLButtonElement>;`
- `type?: "button" | "submit" | "reset" | undefined;`

### `ToggleOwnProps`

Import from `@askrjs/ui/toggle`.

- `children?: unknown;`
- `disabled?: boolean | undefined;`
- `onPress?: ((e: PressEvent) => void) | undefined;`
- `pressed?: boolean | undefined;`

### `ToggleProps`

Import from `@askrjs/ui/toggle`.

- `asChild?: boolean | undefined;`
- `children?: unknown;`
- `disabled?: boolean | undefined;`
- `onPress?: ((e: PressEvent) => void) | undefined;`
- `pressed?: boolean | undefined;`
- `ref?: ((value: Element | null) => void) | { current: Element | null; } | ((value: HTMLButtonElement | null) => void) | { current: HTMLButtonElement | null; } | null | undefined;`
- `type?: "button" | "submit" | "reset" | undefined;`

### `ToggleGroupItemAsChildProps`

Import from `@askrjs/ui/toggle-group`.

- `asChild: true;`
- `children: JSXElement;`
- `disabled?: boolean | undefined;`
- `onPress?: ((event: PressEvent) => void) | undefined;`
- `ref?: Ref<Element>;`
- `type?: undefined;`
- `value: string;`

### `ToggleGroupItemOwnProps`

Import from `@askrjs/ui/toggle-group`.

- `children?: unknown;`
- `disabled?: boolean | undefined;`
- `value: string;`

### `ToggleGroupItemProps`

Import from `@askrjs/ui/toggle-group`.

- `asChild?: false | undefined;`
- `children?: unknown;`
- `disabled?: boolean | undefined;`
- `onPress?: ((event: PressEvent) => void) | undefined;`
- `ref?: Ref<HTMLButtonElement>;`
- `type?: "button" | "submit" | "reset" | undefined;`

### `ToggleGroupMultipleProps`

Import from `@askrjs/ui/toggle-group`.

- `asChild?: false | undefined;`
- `children?: unknown;` — Supports literal, nested, array-mapped, and `For`-rendered descendants.
- `defaultValue?: string[] | undefined;`
- `disabled?: boolean | undefined;`
- `id?: string | undefined;`
- `loop?: boolean | undefined;`
- `onValueChange?: ((value: string[]) => void) | undefined;`
- `orientation?: ToggleGroupOrientation | undefined;`
- `ref?: Ref<HTMLDivElement>;`
- `type: "multiple";`
- `value?: string[] | undefined;`

### `ToggleGroupProps`

Import from `@askrjs/ui/toggle-group`.

- `asChild?: false | undefined;`
- `children?: unknown;` — Supports literal, nested, array-mapped, and `For`-rendered descendants.
- `defaultValue?: string | string[] | undefined;`
- `disabled?: boolean | undefined;`
- `id?: string | undefined;`
- `loop?: boolean | undefined;`
- `onValueChange?: ((value: string[]) => void) | ((value: string) => void) | undefined;`
- `orientation?: ToggleGroupOrientation | undefined;`
- `ref?: Ref<HTMLDivElement>;`
- `type?: "single" | "multiple" | undefined;`
- `value?: string | string[] | undefined;`

### `ToggleGroupSingleProps`

Import from `@askrjs/ui/toggle-group`.

- `asChild?: false | undefined;`
- `children?: unknown;` — Supports literal, nested, array-mapped, and `For`-rendered descendants.
- `defaultValue?: string | undefined;`
- `disabled?: boolean | undefined;`
- `id?: string | undefined;`
- `loop?: boolean | undefined;`
- `onValueChange?: ((value: string) => void) | undefined;`
- `orientation?: ToggleGroupOrientation | undefined;`
- `ref?: Ref<HTMLDivElement>;`
- `type?: "single" | undefined;`
- `value?: string | undefined;`

## Purpose

This page covers two related but distinct primitives: `Toggle`, a single pressed/unpressed button (bold, italic, favorite-star patterns), and `ToggleGroup`, a set of toggle buttons where selecting one can affect the others — either a single-select group like alignment buttons or a multi-select group like text formatting. They share the same pressed-state model but solve different layout problems, which is why they're documented together rather than as a combined component.

## Install and import

Both primitives ship from `@askrjs/ui` with their own subpaths — `@askrjs/ui/toggle` and `@askrjs/ui/toggle-group` — and matching `@askrjs/themes/toggle` and `@askrjs/themes/toggle-group` JS subpaths that re-export the same components; there's no separate `toggle.css` file, just `toggle-group.css` in the default theme covering both, loaded the same way as every other component's styling (via `@askrjs/themes/default`, not per-subpath). Import only the JS subpath you need; a page that just needs a single toggle button doesn't have to pull in the group's item-collection logic.

## Live examples

The examples include a standalone `Toggle` for a single boolean action, a single-select `ToggleGroup` (`type="single"`) for mutually exclusive choices like text alignment, and a multi-select `ToggleGroup` (`type="multiple"`) for independent choices like bold/italic/underline stacked together.

## Anatomy

`Toggle` is a standalone component with no required children structure beyond its own content. `ToggleGroup` is a root that wraps one or more `ToggleGroupItem` children, each identified by a required `value` string — the group reads its items' values to compute what's selected rather than you tracking indices.

## State model

`Toggle`'s `pressed` prop is deliberately controlled-only — there's no `defaultPressed` or internal fallback, so you own the boolean and respond to `onPress`. `ToggleGroup` splits on its `type` discriminant: `type="single"` (the default) uses a string `value`/`defaultValue`/`onValueChange`, while `type="multiple"` switches all three to arrays of strings. Passing the wrong shape for the chosen `type` is a type error, not a runtime surprise.

## Keyboard and accessibility

`Toggle` uses `role="button"` with `aria-pressed` and responds to both Enter and Space, and its types explicitly prohibit `onClick` in favor of `onPress` — the package's own docs note this is because `onClick` doesn't carry toggle or disabled semantics the way the pressable foundation's `onPress` does. `ToggleGroup` exposes a `loop` prop that controls whether arrow-key navigation wraps from the last item back to the first, and the group itself carries `role="group"` while each item keeps `role="button"` with `aria-pressed`.

## Styling and tokens

Both components expose `data-state` (`on`/`off` for Toggle, similar semantics per item in a group) and `data-disabled` for CSS targeting, plus `data-orientation` on `ToggleGroup` so horizontal and vertical layouts can be styled independently. `@askrjs/themes` applies the shared button-like visual language here, so a themed `Toggle` looks consistent with `Button` at rest and simply adds a pressed treatment.

## API

`Toggle` takes `pressed`, `onPress`, `disabled`, and the usual `asChild` escape hatch. `ToggleGroup` takes `type`, the value props matching that type, `orientation`, `loop`, and `disabled` (which cascades to disable the whole group); `ToggleGroupItem` takes its own `value`, optional `disabled`, and `asChild`, letting individual items opt out independently of the group-level flag.

## Edge cases

Disabling `ToggleGroup` at the root disables every item regardless of each item's own `disabled` prop, but the reverse isn't true — you can disable individual items in an otherwise enabled group. Because `ToggleGroupItem`'s `value` is required, forgetting to set one is a compile-time error rather than something that silently breaks selection at runtime.

## Related pages

For a single always-visible on/off control tied to a setting rather than a pressed visual, Switch is usually the better fit. If your toggle group is really acting as a segmented tab selector, look at Tabs instead — the visual overlap is common but the semantics differ.

## Documentation navigation

[Previous](https://askrjs.com/docs/components/switch/index.md) | [Next](https://askrjs.com/docs/components/form-label-field-and-input-group/index.md)
