Askr
UI & Components

Toggle Family

Use toggle family with the current published Askr packages.

  • @askrjs/ui/toggle0.0.13
  • @askrjs/ui/toggle-group0.0.13
  • @askrjs/themes/toggle0.0.13
  • @askrjs/themes/toggle-group0.0.13

How to use toggle family

Toggle Family should use the standard themed surface unless the application is deliberately implementing its own design system on top of @askrjs/ui.

  1. Import the themed component from @askrjs/themes/components; use @askrjs/ui directly only when building a custom visual system.
  2. Keep toggle family labels, state, and application actions visible at the call site instead of styling internal DOM nodes.
  3. Verify keyboard behavior, focus movement or return, disabled state, and both standard themes.
import { Toggle, ToggleGroup, ToggleGroupItem } from '@askrjs/themes/components';

<Toggle pressed={bold()} onPressedChange={bold.set}>Bold</Toggle>
<ToggleGroup type="single" value={alignment()} onValueChange={alignment.set}>
  <ToggleGroupItem value="left">Left</ToggleGroupItem>
  <ToggleGroupItem value="center">Center</ToggleGroupItem>
</ToggleGroup>

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` subpaths for styling. Import only the one 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.

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.