Toggle Group
Overview
The Toggle Group is a layout component that arranges related toggles into a single, consistently spaced set — the foundation of a toolbar or a segmented control. The useToggleGroupRecipe() composable creates a fully configured recipe with orientation and size options — a flex container that lays toggles out in a wrapping row or stacks them in a column.
The Toggle Group recipe integrates directly with the Toggle recipe and generates type-safe utility classes at build time with zero runtime CSS.
Why use the Toggle Group recipe?
The Toggle Group recipe helps you:
- Lay out sets consistently: Lay toggles out in a wrapping row or stack them in a column with a single orientation prop.
- Control spacing with one axis: The size variant sets the gap between items, so a whole group scales together.
- Compose, don't couple: The group only handles layout; each child toggle keeps its own color, variant, size, and pressed state.
- Stay type-safe: Full TypeScript support means your editor catches invalid orientation or size values at compile time.
Usage
Register the recipe
Add the Toggle Group recipe to a local Styleframe instance alongside the toggle recipe. The global styleframe.config.ts provides design tokens and utilities, while the component-level file registers the recipes themselves:
import { styleframe } from 'virtual:styleframe';
import { useToggleRecipe, useToggleGroupRecipe } from '@styleframe/theme';
const s = styleframe();
const toggle = useToggleRecipe(s);
const toggleGroup = useToggleGroupRecipe(s);
export default s;
Build the component
Import the toggleGroup runtime function from the virtual module and wrap your toggles in the container:
import { toggleGroup } from "virtual:styleframe";
interface ToggleGroupProps {
orientation?: "horizontal" | "vertical";
size?: "sm" | "md" | "lg";
children?: React.ReactNode;
}
export function ToggleGroup({
orientation = "horizontal",
size = "md",
children,
}: ToggleGroupProps) {
const classes = toggleGroup({ orientation, size });
return (
<div className={classes} role="group">
{children}
</div>
);
}
See it in action
Orientation
The Toggle Group supports two orientation variants that control the layout direction.
Horizontal
The default orientation. Toggles are laid out left-to-right in a wrapping row, aligned to the center — the common layout for toolbars and segmented controls.
Vertical
Toggles are stacked top-to-bottom in a column. Useful for a sidebar of view options.
Orientation Reference
| Orientation | Direction | Notes |
|---|---|---|
horizontal | Left to right (row, wraps) | Default; center-aligned, wraps to the next line when out of space |
vertical | Top to bottom (column) | One toggle per line |
Sizes
Three size variants control the gap between toggles, letting you tighten or loosen a group to match its surroundings. Set the same size on each child toggle so the controls and the spacing scale together.
| Size | Gap |
|---|---|
sm | @0.5 |
md | @0.75 |
lg | @1 |
size controls only the gap between items. Pass the same size to each child <Toggle> so the buttons and the spacing scale as a set.Connected segmented control
The Toggle Group spaces its toggles apart. For a connected segmented control — toggles joined at the seams with no gap — wrap them in the Field Group recipe instead. It merges adjacent border radii and inner borders on any bordered child, so a row of outline toggles reads as one continuous control. There is no attached axis on the Toggle Group; the two layouts are separate, composable tools.
<template>
<FieldGroup>
<Toggle variant="outline" aria-pressed="true">Left</Toggle>
<Toggle variant="outline">Center</Toggle>
<Toggle variant="outline">Right</Toggle>
</FieldGroup>
</template>
outline toggles inside a Field Group so every segment carries the border tokens the seam-merging relies on.Custom
The toggle's content is a slot, so a segmented control can hold richer cells than plain labels. This font-weight picker joins outline toggles with a Field Group and renders an Aa glyph at each weight above a caption — the pressed cell carries the engaged fill.
Accessibility
- Group related toggles. Wrap the toggles in an element with
role="group"and anaria-label(oraria-labelledby) describing the set, so assistive technology announces the context. - Choose single or multiple in your logic. The group is layout only; whether one toggle stays pressed (a segmented, radio-like control) or several can be pressed at once (a checkbox-like set) is behavior you implement, reflected through each toggle's
aria-pressed. - Keep each toggle labelled. Every child still needs its own accessible name (see the Toggle recipe).
Customization
Overriding Defaults
The useToggleGroupRecipe() composable accepts an optional second argument to override any part of the recipe configuration. Overrides are deep-merged with the defaults, so you only need to specify the properties you want to change:
import { styleframe } from 'virtual:styleframe';
import { useToggleGroupRecipe } from '@styleframe/theme';
const s = styleframe();
const toggleGroup = useToggleGroupRecipe(s, {
defaultVariants: {
orientation: 'vertical',
size: 'lg',
},
});
export default s;
Filtering Variants
If you only need a subset of the available variants, use the filter option to limit which values are generated. This reduces the output CSS and keeps your component API focused:
import { styleframe } from 'virtual:styleframe';
import { useToggleGroupRecipe } from '@styleframe/theme';
const s = styleframe();
// Only generate the horizontal orientation
const toggleGroup = useToggleGroupRecipe(s, {
filter: {
orientation: ['horizontal'],
},
});
export default s;
API Reference
useToggleGroupRecipe(s, options?)
Creates a toggle group recipe — a flex container with orientation and size (gap) variants.
Parameters:
| Parameter | Type | Description |
|---|---|---|
s | Styleframe | The Styleframe instance |
options | DeepPartial<RecipeConfig> | Optional overrides for the recipe configuration |
options.base | VariantDeclarationsBlock | Custom base styles for the group |
options.variants | Variants | Custom variant definitions for the recipe |
options.defaultVariants | Record<keyof Variants, string> | Default variant values for the recipe |
options.filter | Record<string, string[]> | Limit which variant values are generated |
Variants:
| Variant | Options | Default |
|---|---|---|
orientation | horizontal, vertical | horizontal |
size | sm, md, lg | md |
Best Practices
- Pair with the Toggle recipe: The group handles layout; each child should use the Toggle recipe for consistent controls.
- Match sizes: Use the same
sizeon the group and its child toggles so spacing and buttons scale together. - Reach for Field Group when segments should touch: Use the Field Group recipe for a connected segmented control; use the Toggle Group when the toggles should stay spaced apart.
- Label the set: Always describe the group's purpose with
aria-labelso screen readers communicate the relationship between options.
FAQ
color, variant, size, and pressed state. Pass the same size to the group and its children if you want the spacing and the buttons to scale together.outline toggles in the Field Group recipe instead — it flattens adjacent radii and inner borders so the segments read as one control.aria-pressed="true" and clear the others when a new one is pressed; for multi-select, let several be pressed at once. The recipe only lays the toggles out.filter option, variant values you exclude are not generated, and default variants are adjusted if they reference a removed value — so the recipe stays consistent and only emits the CSS you use.Toggle
A button-styled two-state control with an on state driven by aria-pressed, solid, outline, and ghost visual styles, light, dark, and neutral surface colors, and three sizes through the recipe system.
ContextMenu
A right-click menu surface for contextual actions. Composed of six coordinated recipes (panel, item, separator, label, shortcut, sub-trigger) with inset, destructive, checkbox/radio, and submenu support across three colors, three visual styles, and three sizes.