Components
Toggle group
Segmented toggle controls for single- or multi-select options.
Wrap .ui-toggle elements in a <ui-toggle-group> (or the equivalent <div class="ui-toggle-group">) to combine them into a single segmented unit. Use radio inputs for single-select and checkbox inputs for multi-select. Add role="group" and aria-label for accessibility.
Single select
Loading components…
<ui-toggle-group role="group" aria-label="Text alignment"> <label class="ui-toggle" data-size="icon"> <input type="radio" name="align" aria-label="Align left" checked /> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" > <line x1="4" y1="6" x2="20" y2="6" /> <line x1="4" y1="12" x2="14" y2="12" /> <line x1="4" y1="18" x2="18" y2="18" /> </svg> </label> <label class="ui-toggle" data-size="icon"> <input type="radio" name="align" aria-label="Align center" /> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" > <line x1="4" y1="6" x2="20" y2="6" /> <line x1="7" y1="12" x2="17" y2="12" /> <line x1="5" y1="18" x2="19" y2="18" /> </svg> </label> <label class="ui-toggle" data-size="icon"> <input type="radio" name="align" aria-label="Align right" /> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" > <line x1="4" y1="6" x2="20" y2="6" /> <line x1="10" y1="12" x2="20" y2="12" /> <line x1="6" y1="18" x2="20" y2="18" /> </svg> </label></ui-toggle-group>/** * toggle-group.css: Toggle group (ui-toggle-group | .ui-toggle-group) * * The :where(ui-button-group, .ui-button-group) structure applied to .ui-toggle children: a single-select set * (radios sharing a `name`) or a multi-select set (checkboxes) fused into one * segmented control. Inner corners are squared and the doubled border collapses to * one seam; the checked/focused/hovered toggle floats above its neighbours. * * @layer components * @requires layers.css, _variables.css, toggle.css * @uses :has(): float the checked/focused toggle above its neighbours * @uses :not(): first/last edge selection for shared-border collapse * @uses logical border-radius longhands: RTL-safe corner rounding per orientation * @see https://ui.shadcn.com/docs/components/base/toggle-group */@layer zazz.components { /* =========================================================================== TOGGLE GROUP Joins adjacent .ui-toggle children into one segmented unit. Children keep their own --ui-toggle-radius, so the outer corners follow the toggles' size variant automatically; only the *inner* corners are squared and the doubled border is collapsed with a -1px overlap. =========================================================================== */ :where(ui-toggle-group, .ui-toggle-group) { display: flex; inline-size: fit-content; /* stretch so mixed-height children share one edge */ align-items: stretch; } /* =========================================================================== TOGGLE GROUP: HORIZONTAL (default) =========================================================================== */ :where(ui-toggle-group, .ui-toggle-group):not([data-orientation="vertical"]) { flex-direction: row; } :where(ui-toggle-group, .ui-toggle-group):not([data-orientation="vertical"]) > :not(:last-child) { border-start-end-radius: 0; border-end-end-radius: 0; } :where(ui-toggle-group, .ui-toggle-group):not([data-orientation="vertical"]) > :not(:first-child) { /* pull onto the previous control's border so the seam is one line, not two */ margin-inline-start: -1px; border-start-start-radius: 0; border-end-start-radius: 0; } /* =========================================================================== TOGGLE GROUP: VERTICAL =========================================================================== */ :where(ui-toggle-group, .ui-toggle-group)[data-orientation="vertical"] { flex-direction: column; } :where(ui-toggle-group, .ui-toggle-group)[data-orientation="vertical"] > :not(:last-child) { border-end-start-radius: 0; border-end-end-radius: 0; } :where(ui-toggle-group, .ui-toggle-group)[data-orientation="vertical"] > :not(:first-child) { margin-block-start: -1px; border-start-start-radius: 0; border-start-end-radius: 0; }}Multi select
Loading components…
<ui-toggle-group role="group" aria-label="Text formatting"> <label class="ui-toggle"> <input type="checkbox" name="format" value="bold" checked /> <span>Bold</span> </label> <label class="ui-toggle"> <input type="checkbox" name="format" value="italic" /> <span>Italic</span> </label> <label class="ui-toggle"> <input type="checkbox" name="format" value="underline" checked /> <span>Underline</span> </label></ui-toggle-group>/** * toggle-group.css: Toggle group (ui-toggle-group | .ui-toggle-group) * * The :where(ui-button-group, .ui-button-group) structure applied to .ui-toggle children: a single-select set * (radios sharing a `name`) or a multi-select set (checkboxes) fused into one * segmented control. Inner corners are squared and the doubled border collapses to * one seam; the checked/focused/hovered toggle floats above its neighbours. * * @layer components * @requires layers.css, _variables.css, toggle.css * @uses :has(): float the checked/focused toggle above its neighbours * @uses :not(): first/last edge selection for shared-border collapse * @uses logical border-radius longhands: RTL-safe corner rounding per orientation * @see https://ui.shadcn.com/docs/components/base/toggle-group */@layer zazz.components { /* =========================================================================== TOGGLE GROUP Joins adjacent .ui-toggle children into one segmented unit. Children keep their own --ui-toggle-radius, so the outer corners follow the toggles' size variant automatically; only the *inner* corners are squared and the doubled border is collapsed with a -1px overlap. =========================================================================== */ :where(ui-toggle-group, .ui-toggle-group) { display: flex; inline-size: fit-content; /* stretch so mixed-height children share one edge */ align-items: stretch; } /* =========================================================================== TOGGLE GROUP: HORIZONTAL (default) =========================================================================== */ :where(ui-toggle-group, .ui-toggle-group):not([data-orientation="vertical"]) { flex-direction: row; } :where(ui-toggle-group, .ui-toggle-group):not([data-orientation="vertical"]) > :not(:last-child) { border-start-end-radius: 0; border-end-end-radius: 0; } :where(ui-toggle-group, .ui-toggle-group):not([data-orientation="vertical"]) > :not(:first-child) { /* pull onto the previous control's border so the seam is one line, not two */ margin-inline-start: -1px; border-start-start-radius: 0; border-end-start-radius: 0; } /* =========================================================================== TOGGLE GROUP: VERTICAL =========================================================================== */ :where(ui-toggle-group, .ui-toggle-group)[data-orientation="vertical"] { flex-direction: column; } :where(ui-toggle-group, .ui-toggle-group)[data-orientation="vertical"] > :not(:last-child) { border-end-start-radius: 0; border-end-end-radius: 0; } :where(ui-toggle-group, .ui-toggle-group)[data-orientation="vertical"] > :not(:first-child) { margin-block-start: -1px; border-start-start-radius: 0; border-start-end-radius: 0; }}Vertical
Add data-orientation="vertical" to stack items:
Loading components…
<ui-toggle-group data-orientation="vertical" role="group" aria-label="Map layer"> <label class="ui-toggle"> <input type="radio" name="layer" value="map" checked /> <span>Map</span> </label> <label class="ui-toggle"> <input type="radio" name="layer" value="satellite" /> <span>Satellite</span> </label> <label class="ui-toggle"> <input type="radio" name="layer" value="terrain" /> <span>Terrain</span> </label></ui-toggle-group>/** * toggle-group.css: Toggle group (ui-toggle-group | .ui-toggle-group) * * The :where(ui-button-group, .ui-button-group) structure applied to .ui-toggle children: a single-select set * (radios sharing a `name`) or a multi-select set (checkboxes) fused into one * segmented control. Inner corners are squared and the doubled border collapses to * one seam; the checked/focused/hovered toggle floats above its neighbours. * * @layer components * @requires layers.css, _variables.css, toggle.css * @uses :has(): float the checked/focused toggle above its neighbours * @uses :not(): first/last edge selection for shared-border collapse * @uses logical border-radius longhands: RTL-safe corner rounding per orientation * @see https://ui.shadcn.com/docs/components/base/toggle-group */@layer zazz.components { /* =========================================================================== TOGGLE GROUP Joins adjacent .ui-toggle children into one segmented unit. Children keep their own --ui-toggle-radius, so the outer corners follow the toggles' size variant automatically; only the *inner* corners are squared and the doubled border is collapsed with a -1px overlap. =========================================================================== */ :where(ui-toggle-group, .ui-toggle-group) { display: flex; inline-size: fit-content; /* stretch so mixed-height children share one edge */ align-items: stretch; } /* =========================================================================== TOGGLE GROUP: HORIZONTAL (default) =========================================================================== */ :where(ui-toggle-group, .ui-toggle-group):not([data-orientation="vertical"]) { flex-direction: row; } :where(ui-toggle-group, .ui-toggle-group):not([data-orientation="vertical"]) > :not(:last-child) { border-start-end-radius: 0; border-end-end-radius: 0; } :where(ui-toggle-group, .ui-toggle-group):not([data-orientation="vertical"]) > :not(:first-child) { /* pull onto the previous control's border so the seam is one line, not two */ margin-inline-start: -1px; border-start-start-radius: 0; border-end-start-radius: 0; } /* =========================================================================== TOGGLE GROUP: VERTICAL =========================================================================== */ :where(ui-toggle-group, .ui-toggle-group)[data-orientation="vertical"] { flex-direction: column; } :where(ui-toggle-group, .ui-toggle-group)[data-orientation="vertical"] > :not(:last-child) { border-end-start-radius: 0; border-end-end-radius: 0; } :where(ui-toggle-group, .ui-toggle-group)[data-orientation="vertical"] > :not(:first-child) { margin-block-start: -1px; border-start-start-radius: 0; border-start-end-radius: 0; }}API
| Attribute | Values |
|---|---|
data-orientation | vertical (omit = horizontal default) |
Outer corners adapt to child --ui-toggle-radius tokens automatically.