Components

Toggle Group

A set of Toggles with one value, after Base UI's ToggleGroup: text alignment (one pressed at a time) or text style (several). <lu-toggle-group role="group"> presses its toggles and gives the group one tab stop that the arrow keys, Home and End move, following the orientation and the direction, on server pages and in islands. bind:value keeps a signal in sync.

Aligned: left.

A live demo, with the default theme. Its code
ts
import { Toggle, ToggleGroup } from "@lumiose/ui"; // or "@lumiose/ui/toggle" and "@lumiose/ui/toggle-group"
import "@lumiose/ui/themes/default.css"; // optional: the default theme

#Anatomy

tsx
<ToggleGroup aria-label="Alignment">
  <Toggle value="left">Left</Toggle>
  <Toggle value="center">Center</Toggle>
</ToggleGroup>
Part Renders
ToggleGroup <lu-toggle-group role="group" data-orientation>; multiple if set
Toggle <button aria-pressed value>; the group's tab stop has tabindex="0"

#API

#ToggleGroup

Prop Type Default
value string[] The pressed toggles. Pair it with onValueChange, which updates it.
defaultValue string[] [] The toggles pressed at first.
onValueChange (value: string[]) => void Called after the user presses or releases a toggle.
bind:value Signal<string[]> Stands in for value and onValueChange.
multiple boolean false Several toggles can be pressed; otherwise pressing one releases the other.
orientation "horizontal" | "vertical" "horizontal" Which arrow keys move focus.
loopFocus boolean true The arrow keys go from the last toggle to the first, and back.
disabled boolean false Disables every toggle.

Every other prop passes through to <lu-toggle-group>: aria-label, aria-labelledby, id, class. Name the group with one of the first two.

With value, the group is controlled: after the user presses or releases a toggle, the toggles show value again, so a press shows only once onValueChange has updated value with it. One that leaves value as it was keeps the toggles as they were: an onValueChange that ignores an empty array keeps one toggle pressed. Setting value to the toggles already pressed does nothing.

Each toggle's value is its identity in the group; its onPressedChange still fires. A pressedchange event (detail.pressed) bubbles from a toggle before it changes, and event.preventDefault() cancels the change.

Differences from Base UI's ToggleGroup. No render. Focus follows tabindex on the toggles (roving), as Base UI does; disabled toggles are natively disabled, so focus skips them.

#Example

Live at the top of the page: an island
tsx
import { Toggle } from "@lumiose/ui/toggle";
import { ToggleGroup } from "@lumiose/ui/toggle-group";
import { signal } from "lumiose";

export function TextAlignment() {
  const align = signal<string[]>(["left"]);
  return (
    <p>
      <ToggleGroup aria-label="Text alignment" bind:value={align} class="lu-toggle-group">
        <Toggle value="left" class="lu-toggle">
          Left
        </Toggle>
        <Toggle value="center" class="lu-toggle">
          Center
        </Toggle>
        <Toggle value="right" class="lu-toggle">
          Right
        </Toggle>
      </ToggleGroup>{" "}
      Aligned: {align()[0] ?? "none"}.
    </p>
  );
}

#Styling

With the default theme, put lu-toggle-group on the group and lu-toggle on each toggle: the toggles in a row with a small gap, in a column when data-orientation="vertical".

With your own CSS, style the group by [data-orientation] and [multiple], and the toggles by [aria-pressed="true"], :focus-visible and :disabled.

Toggle Group ships no stylesheet: it needs none to work.

#Keyboard and focus

Key Does
Tab Enters the group on the last focused toggle (at first, the first pressed or the first enabled), and leaves it.
Arrow Right / Arrow Left Horizontal: the next or previous toggle (swapped right to left), looping.
Arrow Down / Arrow Up Vertical: the next or previous toggle, looping.
Home / End The first or last enabled toggle.
Enter / Space Presses or releases the focused toggle.

Arrows move focus without pressing, and skip disabled toggles. With loopFocus={false} they stop at the ends.

Inside a Toolbar, the group still presses its toggles, but the toolbar's arrow keys and single tab stop take over: the toggles are toolbar items.

#Without JavaScript, and the element's script

The server HTML has each toggle's aria-pressed and the tab stop. <lu-toggle-group>'s script (1.0 kB brotli) presses the toggles and moves focus, on server pages and in islands; when the tab stop's toggle goes or is disabled, or a disabled group is enabled, the first pressed (else enabled) toggle takes the tab stop. With no script at all the toggles show their state but do not change. For values a form submits, use a Checkbox Group or a Radio group.

#Browser support

Custom elements and aria-pressed: every supported browser.

  • Toggle: one toggle, on its own or in a group.
  • Radio: one choice submitted with a form.
  • Tabs: toggles that switch panels.