Skip to content

ToggleGroup ​

A mutually exclusive button group for single/multiple selection: single mode uses radio semantics, multiple mode uses checkbox semantics; keyboard arrow and Home/End navigation and controlled value. Supports size steps, vertical layout, attached form, item icons, mandatory selection, multiple-select limit, spread, selection color and validation status.

ToggleGroup vs ButtonGroup ​

  • oas-toggle-group (this component): state selection — a controlled set of selected states via value, radio/checkbox semantics (aria-checked), single/multiple modes, roving keyboard, and form capabilities such as mandatory / max-count / status. Suited to view switching, filter conditions and rich-text style toggles.
  • oas-button-group: action orchestration — buttons each trigger their own action (oas-click) with no selected-state semantics; it also keeps a value / multiple selection form for compatibility, and new code for state-selection scenarios is recommended to use toggle-group (fuller ARIA semantics and keyboard model).

Single Select ​

Without multiple, it is single-select (role="radiogroup" + radio); value is a string, and only one item is pressed at a time.

Single select

Current: day

Multiple Select ​

With multiple, it becomes multi-select (role="group" + checkbox); value is a JSON array string.

Multiple select

Current: []

Disabled ​

Item-level disabled: true disables that item; disabled items are skipped in keyboard navigation.

Disabled items

Controlled Selection (value) ​

value is a controlled channel: a string for single select, a JSON array string for multiple; externally setting the attribute immediately reflects in the selected state (clicks inside the group also write back the attribute). The buttons below drive the selection externally:

Controlled value

Single: DaySingle: MonthMultiple: Italic + Underline

Presetting value="week" / value='["bold"]' gives both groups an initial selected state; writing the value attribute externally switches the selected state immediately.

Declarative Child-Element Channel ​

Besides the items JSON, you can declare options declaratively with <oas-toggle-item> child elements (the items attribute takes precedence when explicitly set; otherwise child elements are parsed and converge into the same rendering path). The default slot text is the label; attributes map to the ToggleItem fields: value / disabled / icon / aria-label. Child additions, removals, attribute and text changes re-render automatically (MutationObserver); single/multiple (multiple) semantics are identical to the items channel.

Declarative child elements (single + multiple)

DayWeekMonth (disabled)BoldItalicUnderlineAdd one dynamically

Size Steps (size) ​

size has three steps: small / medium (default) / large; control height and font size follow global tokens. When not set explicitly, the config-provider size injection is respected (global density). Use small inside tables and large on filter bars:

Size steps

Item Icons (icon / icon-only) ​

Add an icon field to an items entry (or the icon attribute on a child element) to render an icon before the text (an @oas-ui/icons registry name). An icon item without a label automatically becomes icon-only (square), with the icon name as the fallback accessible name — prefer providing a precise name via the ariaLabel field; labeled items can also override the accessible name with ariaLabel (e.g. "B" read as "Bold").

A rich-text toolbar is the classic scenario — text styles as multiple, alignment as single:

Rich-text toolbar (multiple + single + icon-only)

BIUSLeftCenterRightStyle: bold | Align: left

Vertical Layout (vertical) ​

The vertical boolean switches to a vertical group (syncing aria-orientation="vertical"); combined with icon-only items it is the classic view-switching form:

Vertical view switching (vertical + icon-only single)

View: list

The right group shows the attached vertical form. Long-option vertical groups with labels work the same way: vertical plus plain items.

Attached Form (attached) ​

The default is detached (a gap between buttons, each with its own radius — unchanged behavior); the attached boolean enables attached — zero gap, adjacent borders merged to 1px, and only the group ends keep rounded corners (left/right in horizontal, top/bottom in vertical; logical properties adapt to RTL). Hover / focus / selected items automatically raise above neighbors so their borders are not clipped:

Detached (default) vs attached

Group Variant (variant) ​

The variant group-level variant passes through to every toggle item (aligned with the oas-button variant system): solid (default, bordered box, selected = solid fill) / outlined (transparent background with border; selected = primary border + faint tint) / filled (soft tinted background, no border; selected = solid fill) / text (no border or background; selected = faint tint + primary text). Invalid values silently fall back to solid; orthogonal to attached / vertical / color / status (status colors win). View switches and rich-text style groups suit attached + solid; filter panels suit filled or outlined:

Four variants (selected-state comparison)

Align: []

Spread (spread) ​

The spread boolean makes the group fill the parent width with equal-width items (mobile action bars / filter bars); vertical groups also fill the width:

Mobile action bar (spread)

Mandatory Selection (mandatory) ​

  • mandatory (boolean): the last selected item in multiple mode cannot be deselected (click/keyboard intercepted, no event dispatched); single mode is radio semantics and naturally never empty.
  • mandatory="force": implies the interception above, and auto-selects the first non-disabled item when empty — no initial value, value cleared, value pointing to a missing item, or options changing so the value dangles all trigger the fallback. Wizard flows (day/week/month must have one) need zero host code:

Mandatory (force wizard flow + multiple mandatory)

Stat period (force, no initial value):Export formats (multiple mandatory, keep at least one):Period: day | Formats: pdf

Note: the force fallback only writes the value attribute and does not dispatch oas-change (not a user interaction; the value attribute is the controlled source of truth) — hosts can listen for attribute changes or read value.

Multiple-Select Limit (max-count) ​

max-count (effective only with multiple) caps the number of selected items: once the cap is reached, unselected items are greyed out (same visuals as disabled, aria-disabled synced), clicks/keyboard are intercepted and oas-exceed-limit is dispatched (detail: { value, max }); selected items can still be deselected, after which greyed items become selectable again. Invalid values / 0 / negatives mean no cap; single mode is unaffected:

Multiple-select limit (max-count + oas-exceed-limit)

Selected 1 / 2

Selection Color (color) ​

color follows the unified ui-spec protocol: any CSS color value (#0e7490 / rgb(...), text color auto black/white by luminance) takes precedence; the 11 preset names (magenta / red / volcano / orange / gold / lime / green / cyan / blue / geekblue / purple) resolve to --oas-preset-* tokens (light/dark adaptive); default is the primary color. Theme-level batch customization goes through the CSS variables --oas-toggle-color / --oas-toggle-on-color:

Selection color (color)

Form Validation (status) ​

status has three states: success / warning / error: unselected item borders take the semantic color, selected items are fully tinted, and the focus ring is dyed to match; error syncs the host aria-invalid (a host-set aria-invalid="true" is equivalent to the error visuals). Submit-validation scenario:

Form validation (status)

Channels:SaveSelect at least one channel

Events ​

Clicking or keyboard toggling dispatches oas-change; single select: detail: { value: string }, multiple select: detail: { value: string[] }.

Change events

oas-change: { value: "left" }

API ​

oas-toggle-group ​

Attributes ​

AttributeDescriptionTypeDefault
aria-labelGroup accessible name (host override; falls back to locale default)——
attachedAttached form: adjacent items share borders, end radii only (default detached)——
colorSelected color: preset name or any CSS color (auto text color)string—
disabledDisables the whole toggle group (explicitly, or inherited from the config-provider global disabled injection)boolean—
itemsOptions JSON (property assignment reflects to attribute)ToggleItem[] | string[]
mandatoryMandatory selection: boolean = the sole selected item cannot be deselected; force = auto-select the first enabled item when empty (wizard flow, zero host code)——
max-countMulti-select limit: at the limit unselected items grey out and oas-exceed-limit fires; selected items stay removablestring—
multipleMultiple mode (checkbox semantics)boolean—
sizeSize preset small / medium (default) / largestringmedium
spreadFull-width equal split (aligned with button-group spread)——
statusValidation status: error / warning / success (unselected border + selected block tint)string—
valueCurrent value: string for single; JSON array string for multiplestring | string[][]
variantGroup-level variant passthrough to items (aligned with the button variant system): solid (default, bordered box, selected = solid fill) / outlined (transparent bg + border; selected = colored border + faint tint) / filled (soft tinted bg, no border; selected = solid fill) / text (no border/background; selected = faint tint + colored text); invalid values silently fall back to solid; orthogonal to attached/verticalstring—
verticalVertical arrangement (mirrors aria-orientation and axis keys)boolean—

Property (JS property; see each row for attribute reflection) ​

PropertyDescriptionTypeDefault
valueCurrent value: the selected value string, or an array of selected values when multiplestring | string[]—

Events ​

EventDescription
oas-changeToggle, detail: { value: string | string[] }
oas-exceed-limitSelection attempt past max-count, detail: { value, max }

CSS Variables ​

CSS VariableDefault
--oas-toggle-colorvar(--oas-color-primary)
--oas-toggle-on-colorvar(--oas-color-text-on-primary)
--oas-toggle-tint-textvar(--oas-color-primary-text)

oas-toggle-item ​

Attributes ​

AttributeDescriptionTypeDefault
aria-labelItem accessible name (required semantics for icon-only items; derived from the icon name by default)——
disabledDisable this item (not clickable; skipped by arrow keys)——
iconIcon (oas-icon name); label optional (icon-only items)——
valueItem value (data-carrier field of the declarative child-element channel)——

Slots ​

NameDescription
defaultButton label (default slot text)

ToggleItem fields:

FieldDescriptionType
labelButton label (omittable for icon-only items)string
valueValue (returned with events)string
disabledDisable this itemboolean
iconLeading icon (@oas-ui/icons registry name); without a label the item becomes icon-onlystring
ariaLabelItem-level accessible-name override (fallback: label text; icon name for icon-only items)string

Keyboard: in single mode arrow keys move and select (radio group convention); in multiple mode arrow keys move focus (roving tabindex) and Space/Enter toggle; Home/End jump to the first/last enabled item (disabled items skipped). The container has role="radiogroup" / role="group" + aria-label (a host aria-label attribute overrides the locale fallback); selected items expose aria-checked; vertical syncs aria-orientation="vertical".

Released under the MIT OR Apache-2.0 License.