Components
Toggle
A button that keeps its pressed state: formatting, column sets, and any on/off that is not a switch.
Examples
Pressed and unpressed
A pressed toggle keeps its surface and takes the inset well, so it reads as a switch that has been pushed rather than a tab that has been selected.
<Toggle variant="outline" label="Bold"><RiBold /></Toggle>
<Toggle variant="outline" label="Italic"><RiItalic /></Toggle>
<Toggle variant="soft" defaultPressed label="Show ranges"><RiListCheck2 /> Ranges</Toggle>
<Toggle label="Disabled" disabled>Off</Toggle>A group: multiple or single
Multiple keeps every item independent. Single is a radiogroup — one tab stop, arrow keys, aria-checked — which is a different contract from a sliding segmented control.
multiple
Any number of options may be on at once (column visibility, overlays, layers).
single
Exactly one option is on (aggregation, density, mode).
SegmentedControl is one value with a sliding indicator. ToggleGroup is a set of independent options. They look related and are not interchangeable: a segmented control that allowed two selections would be a lie about the state.
<ToggleGroup type="multiple" defaultValue={["price", "volume"]} aria-label="Columns">
<ToggleGroupItem value="price">Price</ToggleGroupItem>
<ToggleGroupItem value="volume">Volume</ToggleGroupItem>
<ToggleGroupItem value="funding">Funding</ToggleGroupItem>
</ToggleGroup>
<ToggleGroup type="single" defaultValue="d1" aria-label="Aggregation">
<ToggleGroupItem value="h1">1h</ToggleGroupItem>
<ToggleGroupItem value="d1">1d</ToggleGroupItem>
<ToggleGroupItem value="w1">1w</ToggleGroupItem>
</ToggleGroup>A toolbar
A toolbar is one tab stop. A screen-reader user should not have to press Tab eleven times to cross a formatting strip.
<Toolbar label="Formatting">
<ToolbarToggleGroup
type="multiple"
defaultValue={["bold"]}
aria-label="Text style"
className="flex items-center gap-1"
>
<ToolbarToggleItem
value="bold"
aria-label="Bold"
className={cn(toggleVariants({ variant: "outline", size: "sm" }), "px-2")}
>
<RiBold />
</ToolbarToggleItem>
<ToolbarToggleItem
value="italic"
aria-label="Italic"
className={cn(toggleVariants({ variant: "outline", size: "sm" }), "px-2")}
>
<RiItalic />
</ToolbarToggleItem>
</ToolbarToggleGroup>
<ToolbarSeparator />
<ToolbarToggleGroup
type="single"
defaultValue="columns"
aria-label="Layout"
className="flex items-center gap-1"
>
<ToolbarToggleItem
value="columns"
aria-label="Column sets"
className={cn(toggleVariants({ variant: "outline", size: "sm" }), "px-2")}
>
<RiListCheck2 />
</ToolbarToggleItem>
</ToolbarToggleGroup>
</Toolbar>Usage
import { Toggle, ToggleGroup, ToggleGroupItem } from "@luc/ui";<Toggle label="Bold" defaultPressed onPressedChange={applyBold}>
<RiBold />
</Toggle>`pressed` plus `onPressedChange` controls it; `defaultPressed` leaves the state to the component. A group item takes `value` instead, and the group takes `type`.
API
Read from the published TypeScript API, so a prop that is not listed here does not exist and a default that is listed is the one the compiler sees.
| Export | Kind | Signature |
|---|---|---|
Toggle | 8 documented props | ({ className, variant, size, block, label, ...props }: ToggleProps) => import("@types/react").JSX.Element |
ToggleGroup | 10 documented props | ({ className, ...props }: ToggleGroupProps) => import("@types/react").JSX.Element |
ToggleGroupItem | 6 documented props | ({ className, variant, size, label, ...props }: ToggleGroupItemProps) => import("@types/react").JSX.Element |
toggleVariants | export | (props?: ({ variant?: "outline" | "default" | "soft" | null | undefined; size?: "sm" | "md" | "lg" | null | undefined; block?: boolean | null | undefined; } & import("class-variance-authority/dist/ty… |
Toggle props
Type: ToggleProps
Values the compiler reads from the declaration.
| Prop | Type | Default | Notes |
|---|---|---|---|
asChild?inherited | boolean | undefined | — | |
block? | boolean | null | undefined | — | |
defaultPressed?inherited | boolean | undefined | — | The state of the toggle when initially rendered. Use `defaultPressed` if you do not need to control the state of the toggle. |
label? | string | undefined | — | Required for an icon-only toggle; ignored when children carry text. |
onPressedChange?inherited | ((pressed: boolean) => void) | undefined | — | The callback that fires when the state of the toggle changes. |
pressed?inherited | boolean | undefined | — | The controlled state of the toggle. |
size? | "sm" | "md" | "lg" | null | undefined | — | |
variant? | "outline" | "default" | "soft" | null | undefined | — |
ToggleGroup props
Type: (RadixToggleGroup.ToggleGroupSingleProps | RadixToggleGroup.ToggleGroupMultipleProps) & RefAttributes<HTMLDivElement>
Values the compiler reads from the declaration.
| Prop | Type | Default | Notes |
|---|---|---|---|
asChild?inherited | boolean | undefined | — | |
defaultValue?inherited | string | string[] | undefined | — | The value of the item that is pressed when initially rendered. Use `defaultValue` if you do not need to control the state of a toggle group. The value of the items that are presse… |
dir?inherited | Direction | undefined | — | |
disabled?inherited | boolean | undefined | — | Whether the group is disabled from user interaction. |
loop?inherited | boolean | undefined | — | |
onValueChange?inherited | ((value: string) => void) | ((value: string[]) => void) | undefined | — | The callback that fires when the value of the toggle group changes. The callback that fires when the state of the toggle group changes. |
orientation?inherited | "horizontal" | "vertical" | undefined | — | |
rovingFocus?inherited | boolean | undefined | — | Whether the group should maintain roving focus of its buttons. |
typeinherited | "single" | "multiple" | — | |
value?inherited | string | string[] | undefined | — | The controlled stateful value of the item that is pressed. The controlled stateful value of the items that are pressed. |
ToggleGroupItem props
Type: ToggleGroupItemProps
Values the compiler reads from the declaration.
| Prop | Type | Default | Notes |
|---|---|---|---|
asChild?inherited | boolean | undefined | — | |
block? | boolean | null | undefined | — | |
label? | string | undefined | — | |
size? | "sm" | "md" | "lg" | null | undefined | — | |
valueinherited | string | — | A string value for the toggle group item. All items within a toggle group should use a unique value. |
variant? | "outline" | "default" | "soft" | null | undefined | — |
Guidelines
Do
- Use a `Toggle` for an action that applies immediately to what the reader is looking at, and show the state rather than a label that changes.
- Give an icon-only toggle a `label`: it becomes the accessible name, and the pressed state is announced separately.
- Use `type="multiple"` when the choices are independent, and `type="single"` when exactly one can hold.
Don't
- Use a `Toggle` to submit a form — that is a `Button`.
- Use a `Toggle` for an on/off setting that persists — that is a `Switch`.
- Put a `ToggleGroup` beside a `SegmentedControl` in one toolbar: they look similar and mean different things, one a set of independent options and the other a single value.
Accessibility
A `Toggle` is a two-state button that reports `aria-pressed`, so assistive technology hears the state rather than a changed label. A `ToggleGroup` is a roving-focus composite where each item keeps its own pressed state; `type="single"` behaves as a radio group and always has one choice.
ButtonGroup and Toolbar are one module, documented together on the ButtonGroup page.
Related