7.0 KiB
ToggleGroup
(no submodules)
- toggle-group.variants — `toggleGroupVariants` and `…-
toggle-group.variants —
toggleGroupVariantsandtoggleGroupItemVariantsare the cva (class-variance-authority) configurations powering `<To… -
toggle-group.variants —
toggleGroupVariantsand `… -
toggle-group.variants —
toggleGroupVariantsandtoggleGroupItemVariantsare the cva (class-variance-authority) configurations powering `<To… -
toggle-group.variants —
toggleGroupVariantsand `… -
toggle-group.variants —
toggleGroupVariantsandtoggleGroupItemVariantsare the cva (class-variance-authority) configurations powering `<To… -
toggle-group.variants —
toggleGroupVariantsand `… -
toggle-group.variants —
toggleGroupVariantsandtoggleGroupItemVariantsare the cva (class-variance-authority) configurations powering `<To… -
toggle-group.variants —
toggleGroupVariantsandtoggleGroupItemVariantsare the cva (class-variance-authority) configurations powering `<To…
Purpose
<ToggleGroup> and <ToggleGroupItem> are the chassis option-set picker built on @radix-ui/react-toggle-group. Radix supplies the a11y semantics (role="group", roving tabindex across items, arrow-key navigation, native Space activation, controlled value propagation in both single and multiple modes); the chassis layers cva variant resolution and propagates variant + size to every <ToggleGroupItem> via context so consumers do not need to repeat the props on every item.
Per the shadcn rule, option sets of 2–7 choices use <ToggleGroup>; do not loop <Button> with manual aria-pressed state. The single mode exposes a string value, the multiple mode exposes a string array — both routes preserve the discriminated union in the type signature so consumers get autocomplete on the right shape.
Features
- Two visual variants (
default,outline) shared with<Toggle>for visual coherence. - Three sizes (
sm,default,lg) for dense or roomy toolbars. singleandmultipleselection modes with the discriminatedvalueshape preserved.- Variant + size propagation from group to items via React context (per-item override wins over inherited).
- Roving tabindex across items provided by Radix — only one item is in the tab order at any time.
- Refs forwarded on both
<ToggleGroup>and<ToggleGroupItem>. motion-reduce:transition-nonecollapses transitions forprefers-reduced-motion: reduce.- Theme-driven variant overrides via
useThemedVariants("ToggleGroup" | "ToggleGroupItem").
Usage: Basic Example
import { ToggleGroup, ToggleGroupItem } from "@suaveplan/react-ui";
import { AlignLeftIcon, AlignCenterIcon, AlignRightIcon } from "lucide-react";
export function AlignmentPicker() {
return (
<ToggleGroup type="single" defaultValue="left" aria-label="Text alignment">
<ToggleGroupItem value="left" aria-label="Left align">
<AlignLeftIcon />
</ToggleGroupItem>
<ToggleGroupItem value="center" aria-label="Center align">
<AlignCenterIcon />
</ToggleGroupItem>
<ToggleGroupItem value="right" aria-label="Right align">
<AlignRightIcon />
</ToggleGroupItem>
</ToggleGroup>
);
}
Usage: Advanced Example
import { ToggleGroup, ToggleGroupItem, FieldSet, FieldLegend } from "@suaveplan/react-ui";
import { useState } from "react";
export function FilterPicker() {
const [filters, setFilters] = useState<string[]>([]);
return (
<FieldSet>
<FieldLegend>Filters</FieldLegend>
<ToggleGroup
type="multiple"
value={filters}
onValueChange={setFilters}
variant="outline"
size="sm"
>
<ToggleGroupItem value="open">Open</ToggleGroupItem>
<ToggleGroupItem value="closed">Closed</ToggleGroupItem>
<ToggleGroupItem value="merged">Merged</ToggleGroupItem>
<ToggleGroupItem value="draft">Draft</ToggleGroupItem>
</ToggleGroup>
</FieldSet>
);
}
API Reference
<ToggleGroup>
forwardRef<ComponentRef<typeof ToggleGroupPrimitive.Root>, ToggleGroupProps> — renders the Radix Root with the discriminated-union shape preserved.
ToggleGroupProps
Inherits the discriminated-union shape of Radix ToggleGroupPrimitive.Root ({ type: "single", value?: string } or { type: "multiple", value?: string[] }) minus asChild. Adds:
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
"default" | "outline" |
"default" |
Inherited by every item via context. |
size |
"sm" | "default" | "lg" |
"default" |
Inherited by every item via context. |
Common Radix props consumers will use:
| Prop | Type | Default | Description |
|---|---|---|---|
type |
"single" | "multiple" |
required | Selection mode. |
value |
string | string[] |
uncontrolled | Selected value(s). |
defaultValue |
string | string[] |
none | Initial value(s) for uncontrolled use. |
onValueChange |
(value: string | string[]) => void |
none | Fires on value change. |
disabled |
boolean |
false |
Disables every item. |
<ToggleGroupItem>
forwardRef<ComponentRef<typeof ToggleGroupPrimitive.Item>, ToggleGroupItemProps> — renders a Radix Item.
ToggleGroupItemProps
Inherits every prop from Radix ToggleGroupPrimitive.Item except asChild. Adds:
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
"default" | "outline" |
from group context | Per-item override. |
size |
"sm" | "default" | "lg" |
from group context | Per-item override. |
value |
string |
required | Unique value within the surrounding group. |
toggleGroupVariants / toggleGroupItemVariants
Both bare cva resolvers exported for external composition.
Implementation Notes
- The variant + size propagation uses React context rather than React.cloneElement so deeply-nested item wrappers (
<TooltipTrigger asChild><ToggleGroupItem>...</ToggleGroupItem></TooltipTrigger>) still receive the inherited values. - Per-item
variant/sizeoverrides win over the inherited context values because the cva call resolvesvariant ?? ctx.variantat render time. - The discriminated-union type is preserved at the public surface so consumers get autocomplete on
value: stringfortype: "single"vsvalue: string[]fortype: "multiple". Internally the chassis casts to a relaxed shape because TypeScript cannot narrow the spread back to the original union after the chassis adds its own props. - The chassis NEVER uses
space-x-*for the row layout —flex gap-1flows the same in RTL. - Refs target the Radix Root + Item — consumers can
.focus()programmatically through the forwarded refs.