Installation
Install the following dependencies:
Set up the token layer and the StyleX compiler. See Installation
for states.ts, state-styles.ts and interop.css, which sizes icons.
Install Toggle and the Button it depends on. Toggle
provides the items and the shared group contexts.
Copy and paste the following code into your project.
components/ui/toggle-group.tsx "use client"
import { use , type CSSProperties } from "react"
import { ToggleGroup as ToggleGroupPrimitive } from "@base-ui/react/toggle-group"
import * as stylex from "@stylexjs/stylex"
import type { StyleXStyles } from "@stylexjs/stylex"
import { ButtonGroupContext } from "@/components/ui/button"
import {
Toggle ,
ToggleGroupContext ,
type ToggleProps ,
type ToggleSize ,
type ToggleVariant ,
} from "@/components/ui/toggle"
import { stateStyles } from "@/lib/state-styles"
import { states } from "@/theme/states"
import { color , radius , space } from "@/theme/tokens.stylex"
const styles = stylex . create ({
root : { display : "flex" , width : "fit-content" , alignItems : "stretch" } ,
vertical : { flexDirection : "column" } ,
segmented : {
"--carbon-toggle-group-radius" : radius . lg ,
borderRadius : "var(--carbon-toggle-group-radius)" ,
padding : "3px" ,
color : color . mutedForeground ,
} ,
})
const spacingStyles = stylex . create ({
0 : { gap : space . s0 } ,
0.5 : { gap : space . s0_5 } ,
1 : { gap : space . s1 } ,
1.5 : { gap : space . s1_5 } ,
2 : { gap : space . s2 } ,
3 : { gap : space . s3 } ,
4 : { gap : space . s4 } ,
5 : { gap : space . s5 } ,
6 : { gap : space . s6 } ,
8 : { gap : space . s8 } ,
10 : { gap : space . s10 } ,
12 : { gap : space . s12 } ,
})
const toggleGroupStyles = {
root : styles . root ,
vertical : styles . vertical ,
spacing : spacingStyles ,
segmented : [ states . well , styles . segmented ] ,
}
type ToggleGroupProps < Value extends string > = Omit <
ToggleGroupPrimitive . Props < Value > ,
"className" | "style"
> & {
variant ?: ToggleVariant
size ?: ToggleSize
spacing ? : keyof typeof spacingStyles
xstyle ?: StyleXStyles
className ?: string
style ?: CSSProperties
}
function ToggleGroup < Value extends string = string > ({
variant ,
size ,
spacing = 2 ,
orientation = "horizontal" ,
children ,
xstyle ,
className ,
style ,
... props
} : ToggleGroupProps < Value > ) {
const parent = use ( ToggleGroupContext )
const segments = spacing === 0 && ( variant ?? "default" ) === "default"
const segmented = segments && ! parent ?. onWell
const onWell = segments || !! parent ?. onWell
return (
< ToggleGroupContext value = {{ variant , size , onWell , segmented }} >
< ButtonGroupContext value = { spacing === 0 && ! segments ? { orientation } : null } >
< ToggleGroupPrimitive
data-slot = "toggle-group"
data-variant = { variant ?? "default" }
data-size = { size ?? "default" }
data-spacing = { spacing }
data-orientation = { orientation }
orientation = { orientation }
{ ... props }
{ ... stateStyles (
( state ) => [
styles . root ,
state . orientation === "vertical" && styles . vertical ,
spacingStyles [ spacing ] ,
segmented && [ states . well , styles . segmented ] ,
xstyle ,
] ,
{ className , style } ,
)}
>
{ children }
</ ToggleGroupPrimitive >
</ ButtonGroupContext >
</ ToggleGroupContext >
)
}
function ToggleGroupItem < Value extends string = string > ( props : ToggleProps < Value > ) {
return < Toggle data-slot = "toggle-group-item" { ... props } />
}
export { ToggleGroup , ToggleGroupItem , toggleGroupStyles } Update the import paths to match your project setup.
Usage
Pass multiple to allow more than one selection. value and defaultValue
are arrays in both modes; use onValueChange to control the selection.
RTL support is not included.
Composition
Use ToggleGroupItem for each option.
Outline
Use variant="outline" for an outline style.
Size
Use size to set the size of every item.
Top Bottom Left Right
Top Bottom Left Right
Top Bottom Left Right
Segmented
With spacing={0} and the default variant, the group is a segmented control. The
items sit in a shallow well and the pressed one is raised out of it. Inside a
Toolbar the toolbar is the well, so the group draws
none of its own.
List Board Calendar
List Board Calendar
List Board Calendar
Spacing
With variant="outline", use spacing={0} to join the items, or a spacing step to
separate them.
Top Bottom Left Right
Top Bottom Left Right
Vertical
Use orientation="vertical" to stack items and navigate with the up and down arrow keys.
Disabled
Use disabled on the group to disable every item, or on an item to disable only that option.
Custom
Use xstyle to customize the items and value to keep one weight selected.
Font Weight
Aa Light Aa Normal Aa Medium Aa Bold
Use font-normal to set the font weight.
API reference
ToggleGroup accepts Base UI Toggle Group props .
ToggleGroupItem accepts Toggle props . Both take render,
xstyle, className and real inline style.
ToggleGroup
Prop Type Default variant"default" | "outline""default"size"sm" | "default" | "lg""default"spacing0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 122
Group-level variant and size override item values. When omitted, each item
uses its own value or its default.
toggleGroupStyles
Key What it is rootFitted row with stretching items verticalColumn layout spacingGaps on the token scale segmentedThe well a segmented group draws
Data attributes
Attribute On Effect data-slot="toggle-group"root Targets the group data-slot="toggle-group-item"item Targets an option data-variant, data-sizeroot and items Mirror the variant and size data-spacingroot Mirrors spacing data-orientationroot Mirrors orientation data-disabledroot and items Base UI writes the disabled state data-multipleroot Base UI writes it when multiple selection is enabled data-presseditems Base UI writes the selection state