Styleframe Logo
Forms

Toggle Group

A layout component for arranging a set of toggles with shared orientation and spacing. Supports horizontal and vertical layouts and three gap sizes through the recipe system.

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:

src/components/toggle-group.styleframe.ts
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:

src/components/ToggleGroup.tsx
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

OrientationDirectionNotes
horizontalLeft to right (row, wraps)Default; center-aligned, wraps to the next line when out of space
verticalTop 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.

SizeGap
sm@0.5
md@0.75
lg@1
Good to know: The group's 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.

src/components/SegmentedControl.vue
<template>
    <FieldGroup>
        <Toggle variant="outline" aria-pressed="true">Left</Toggle>
        <Toggle variant="outline">Center</Toggle>
        <Toggle variant="outline">Right</Toggle>
    </FieldGroup>
</template>
Pro tip: Use 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 an aria-label (or aria-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:

src/components/toggle-group.styleframe.ts
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:

src/components/toggle-group.styleframe.ts
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;
Good to know: Filtering also removes compound variants and adjusts default variants that reference filtered-out values, so your recipe stays consistent.

API Reference

useToggleGroupRecipe(s, options?)

Creates a toggle group recipe — a flex container with orientation and size (gap) variants.

Parameters:

ParameterTypeDescription
sStyleframeThe Styleframe instance
optionsDeepPartial<RecipeConfig>Optional overrides for the recipe configuration
options.baseVariantDeclarationsBlockCustom base styles for the group
options.variantsVariantsCustom variant definitions for the recipe
options.defaultVariantsRecord<keyof Variants, string>Default variant values for the recipe
options.filterRecord<string, string[]>Limit which variant values are generated

Variants:

VariantOptionsDefault
orientationhorizontal, verticalhorizontal
sizesm, md, lgmd

Learn more about recipes →

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 size on 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-label so screen readers communicate the relationship between options.

FAQ