ToggleGroup
Set of related toggle buttons that act together as a single, segmented control.
Exposes roving focus, arrow-key navigation, and per-item aria-pressed. Provide an aria-label on the group so its purpose is announced.
Preview
tsx
import { ToggleGroup, ToggleGroupItem } from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<ToggleGroup type="single" defaultValue="left" aria-label="Text alignment">
<ToggleGroupItem value="left">Left</ToggleGroupItem>
<ToggleGroupItem value="center">Center</ToggleGroupItem>
<ToggleGroupItem value="right">Right</ToggleGroupItem>
</ToggleGroup>
);
}
Single vs multiple
Section titled “Single vs multiple”Pass type="single" for mutually exclusive options or type="multiple" for independent toggles.
Preview
tsx
import { ToggleGroup, ToggleGroupItem } from '@arshad-shah/cynosure-react';
import { useState } from 'react';
export default function Example() {
const [align, setAlign] = useState('left');
return (
<ToggleGroup
type="single"
value={align}
onValueChange={(value) => value && setAlign(value)}
variant="outline"
aria-label="Text alignment"
>
<ToggleGroupItem value="left">Left</ToggleGroupItem>
<ToggleGroupItem value="center">Center</ToggleGroupItem>
<ToggleGroupItem value="right">Right</ToggleGroupItem>
<ToggleGroupItem value="justify">Justify</ToggleGroupItem>
</ToggleGroup>
);
}
Preview
tsx
import { ToggleGroup, ToggleGroupItem } from '@arshad-shah/cynosure-react';
import { useState } from 'react';
export default function Example() {
const [marks, setMarks] = useState<string[]>(['bold']);
return (
<ToggleGroup
type="multiple"
value={marks}
onValueChange={setMarks}
variant="outline"
aria-label="Text formatting"
>
<ToggleGroupItem value="bold">Bold</ToggleGroupItem>
<ToggleGroupItem value="italic">Italic</ToggleGroupItem>
<ToggleGroupItem value="underline">Underline</ToggleGroupItem>
</ToggleGroup>
);
}
Variants
Section titled “Variants”ToggleGroup ships three variants — ghost (default), outline, and solid — applied to every item via context.
Preview
tsx
import { ToggleGroup, ToggleGroupItem } from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
<ToggleGroup type="single" defaultValue="a" variant="ghost" aria-label="Ghost group">
<ToggleGroupItem value="a">One</ToggleGroupItem>
<ToggleGroupItem value="b">Two</ToggleGroupItem>
<ToggleGroupItem value="c">Three</ToggleGroupItem>
</ToggleGroup>
<ToggleGroup type="single" defaultValue="a" variant="outline" aria-label="Outline group">
<ToggleGroupItem value="a">One</ToggleGroupItem>
<ToggleGroupItem value="b">Two</ToggleGroupItem>
<ToggleGroupItem value="c">Three</ToggleGroupItem>
</ToggleGroup>
<ToggleGroup type="single" defaultValue="a" variant="solid" aria-label="Solid group">
<ToggleGroupItem value="a">One</ToggleGroupItem>
<ToggleGroupItem value="b">Two</ToggleGroupItem>
<ToggleGroupItem value="c">Three</ToggleGroupItem>
</ToggleGroup>
</div>
);
}
Four sizes are available: xs, sm, md (default), and lg.
Preview
tsx
import { ToggleGroup, ToggleGroupItem } from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<div
style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem', alignItems: 'flex-start' }}
>
<ToggleGroup type="single" defaultValue="a" size="xs" aria-label="Extra small">
<ToggleGroupItem value="a">One</ToggleGroupItem>
<ToggleGroupItem value="b">Two</ToggleGroupItem>
<ToggleGroupItem value="c">Three</ToggleGroupItem>
</ToggleGroup>
<ToggleGroup type="single" defaultValue="a" size="sm" aria-label="Small">
<ToggleGroupItem value="a">One</ToggleGroupItem>
<ToggleGroupItem value="b">Two</ToggleGroupItem>
<ToggleGroupItem value="c">Three</ToggleGroupItem>
</ToggleGroup>
<ToggleGroup type="single" defaultValue="a" size="md" aria-label="Medium">
<ToggleGroupItem value="a">One</ToggleGroupItem>
<ToggleGroupItem value="b">Two</ToggleGroupItem>
<ToggleGroupItem value="c">Three</ToggleGroupItem>
</ToggleGroup>
<ToggleGroup type="single" defaultValue="a" size="lg" aria-label="Large">
<ToggleGroupItem value="a">One</ToggleGroupItem>
<ToggleGroupItem value="b">Two</ToggleGroupItem>
<ToggleGroupItem value="c">Three</ToggleGroupItem>
</ToggleGroup>
</div>
);
}
Attached layout
Section titled “Attached layout”Set attached to render a segmented control — items float as tiles inside a tinted, padded track (the same container NumberInput and ButtonGroup use), with the selected item raised.
Preview
tsx
import { ToggleGroup, ToggleGroupItem } from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<ToggleGroup
type="single"
defaultValue="day"
variant="outline"
attached
aria-label="View range"
>
<ToggleGroupItem value="day">Day</ToggleGroupItem>
<ToggleGroupItem value="week">Week</ToggleGroupItem>
<ToggleGroupItem value="month">Month</ToggleGroupItem>
<ToggleGroupItem value="year">Year</ToggleGroupItem>
</ToggleGroup>
);
}
PropTypeDefaultDescription
type*
"single"|"multiple"
—
value
string|string[]
—
Currently selected value (controlled).
Currently selected values (controlled).
defaultValue
string|string[]
—
Initial selected value (uncontrolled).
Initial selected values (uncontrolled).
onValueChange
((value: string) => void) | ((value: string[]) => void)
—
Fires with the next selected value. Empty string when nothing selected.
Fires with the next array of selected values.
disabled
boolean
—
Whether the group is disabled.
rovingFocus
boolean
—
Whether the group enforces a non-empty selection in single mode.
children
ReactNode
—
Children — should be `<ToggleGroupItem>` elements.
className
string
—
aria-label
string
—
Accessible label for the group.
aria-labelledby
string
—
Reference an external visible label.
size
"xs"|"sm"|"md"|"lg"
"md"
Pixel scale applied to every child toggle via context. One of `xs`, `sm`,
`md`, `lg`.
variant
"ghost"|"outline"|"solid"
"ghost"
Visual style applied to every child toggle via context. One of `ghost`,
`outline`, `solid`.
attached
boolean
—
Render children as a segmented control: items float inside a tinted,
padded track (the same container `NumberInput` and `ButtonGroup` use),
with the selected item raised.
Accessibility
Section titled “Accessibility”- Items expose
aria-pressed(multiple) oraria-checked(single) automatically. - Roving focus + arrow-key navigation moves between items; Home and End jump to ends.
- Always provide an
aria-labelonToggleGroupso screen readers can announce the group purpose. type="single"enforces one active value;type="multiple"allows zero or more.- The shared size and variant cascade through context so individual items stay visually consistent.
Recipes
Section titled “Recipes”- Use single-select groups for mutually exclusive options like text alignment.
- Use multi-select groups for independent formatting toggles (bold, italic, underline).
- Reach for
attachedwhen you want a segmented control look. - Keep groups to a small number of items (3–5) so they stay scannable.