Toggle Group
ui-toggle-group joins ui-toggle children into one control with a shared value. With type="single" at most one
toggle is pressed, like a segmented control. With type="multiple" any number can be pressed, like the bold,
italic and underline buttons of an editor. The value of each ui-toggle identifies it.
The group has the group role and moves focus between its toggles with the arrow keys. It is form-associated, and
the pressed values are submitted under its name, separated by commas.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Toggle Group demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/toggle-group.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/toggle.html"></import-element>
<ui-toggle-group value="left" aria-label="Text alignment">
<ui-toggle value="left" aria-label="Align left">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M3 6h18M3 12h10M3 18h14" /></svg>
</ui-toggle>
<ui-toggle value="center" aria-label="Align center">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M3 6h18M7 12h10M5 18h14" /></svg>
</ui-toggle>
<ui-toggle value="right" aria-label="Align right">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M3 6h18M11 12h10M7 18h14" /></svg>
</ui-toggle>
</ui-toggle-group>
</body>
</html>Examples
Multiple
With type="multiple", each toggle is pressed independently and value lists every pressed toggle.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Toggle Group demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/toggle-group.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/toggle.html"></import-element>
<ui-toggle-group type="multiple" value="bold,underline" aria-label="Text formatting">
<ui-toggle value="bold" variant="outline" aria-label="Bold">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M6 12h9a4 4 0 0 1 0 8H6V4h8a4 4 0 0 1 0 8" /></svg>
</ui-toggle>
<ui-toggle value="italic" variant="outline" aria-label="Italic">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M19 4h-9M14 20H5M15 4 9 20" /></svg>
</ui-toggle>
<ui-toggle value="underline" variant="outline" aria-label="Underline">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M6 4v6a6 6 0 0 0 12 0V4M4 20h16" /></svg>
</ui-toggle>
</ui-toggle-group>
</body>
</html>Outline segmented control
Outline toggles with text make a segmented control. In single mode, clicking the pressed toggle again unpresses it and the value becomes empty.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Toggle Group demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/toggle-group.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/toggle.html"></import-element>
<ui-toggle-group value="week" aria-label="Range">
<ui-toggle value="day" variant="outline">Day</ui-toggle>
<ui-toggle value="week" variant="outline">Week</ui-toggle>
<ui-toggle value="month" variant="outline">Month</ui-toggle>
</ui-toggle-group>
</body>
</html>Listening for changes
The group fires change after every click. Read the new value from the group. The toggles' own change events
stop at the group.
View:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Toggle Group demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/toggle-group.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/toggle.html"></import-element>
<import-element from="./toggle-group-change-demo.html"></import-element>
<toggle-group-change-demo></toggle-group-change-demo>
</body>
</html><custom-element name="toggle-group-change-demo">
<script>
const view = useState({ mode: "grid" });
function changed(group) {
view.mode = group.value || "none";
}
</script>
<style>
:host {
display: flex;
align-items: center;
gap: calc(var(--spacing) * 3);
}
p {
margin: 0;
font-size: var(--text-sm);
color: var(--muted-foreground);
}
</style>
<ui-toggle-group value="grid" aria-label="View" onchange="changed(this)">
<ui-toggle value="list" variant="outline" size="sm">List</ui-toggle>
<ui-toggle value="grid" variant="outline" size="sm">Grid</ui-toggle>
<ui-toggle value="board" variant="outline" size="sm">Board</ui-toggle>
</ui-toggle-group>
<p>View: <slot name="#view.mode"></slot></p>
</custom-element>In a form
The group submits value under its name: one value in single mode, a comma-separated list in multiple mode, or an
empty string when nothing is pressed. Reset returns to the value attribute.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Toggle Group demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/button.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/toggle-group.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/toggle.html"></import-element>
<import-element from="./toggle-group-form-demo.html"></import-element>
<toggle-group-form-demo></toggle-group-form-demo>
</body>
</html><custom-element name="toggle-group-form-demo">
<script>
const result = useState({ text: "Submit the form to see its data." });
function submit(event) {
event.preventDefault();
result.text = [...new FormData(event.target)].map(([name, value]) => `${name}=${value}`).join("\n");
}
function reset() {
result.text = "The form was reset.";
}
</script>
<style>
:host {
display: grid;
gap: calc(var(--spacing) * 4);
width: 100%;
max-width: calc(var(--spacing) * 80);
}
form {
display: grid;
gap: calc(var(--spacing) * 3);
justify-items: start;
}
.actions {
display: flex;
gap: calc(var(--spacing) * 2);
}
output {
display: block;
box-sizing: border-box;
width: 100%;
padding: calc(var(--spacing) * 3);
border-radius: var(--radius-md);
background: var(--muted);
font-family: var(--font-mono);
font-size: var(--text-xs);
white-space: pre-wrap;
}
</style>
<form onsubmit="submit(event)" onreset="reset()">
<ui-toggle-group name="size" value="m" aria-label="Size">
<ui-toggle value="s" variant="outline">S</ui-toggle>
<ui-toggle value="m" variant="outline">M</ui-toggle>
<ui-toggle value="l" variant="outline">L</ui-toggle>
</ui-toggle-group>
<ui-toggle-group name="toppings" type="multiple" aria-label="Toppings">
<ui-toggle value="cheese" variant="outline">Cheese</ui-toggle>
<ui-toggle value="olives" variant="outline">Olives</ui-toggle>
<ui-toggle value="basil" variant="outline">Basil</ui-toggle>
</ui-toggle-group>
<div class="actions">
<ui-button type="submit">Order</ui-button>
<ui-button type="reset" variant="outline">Reset</ui-button>
</div>
</form>
<output><slot name="#result.text"></slot></output>
</custom-element>API
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
type |
"single" | "multiple" |
"single" |
Whether one or several toggles can be pressed. |
value |
string | "" |
Pressed toggle values, separated by commas. The attribute is the initial and reset value. |
orientation |
"horizontal" | "vertical" |
"horizontal" |
Layout direction, and which arrow keys move focus. |
Properties
| Property | Type | Description |
|---|---|---|
value |
string | Pressed values as a comma-separated string. Setting it presses the matching toggles. |
Events
| Event | Detail | Description |
|---|---|---|
change |
none | Fired after a toggle in the group is clicked and value is updated. |
Slots
| Slot | Description |
|---|---|
| (default) | The ui-toggle elements. Every child except the first gets --ui-radius-start: 0, and every child except the last gets --ui-radius-end: 0. |
Child elements
| Element | Attributes read | Description |
|---|---|---|
ui-toggle |
value, pressed |
The group sets each toggle's pressed from its own value. A toggle's value must not contain a comma. |
CSS parts
| Part | Description |
|---|---|
group |
The display: contents wrapper that carries the focusgroup attribute. |
CSS states
| State | Description |
|---|---|
:state(attr-orientation-is-vertical) |
Set for the vertical layout. |
Forms
ui-toggle-group is form-associated and submits value under its name, including an empty string when nothing
is pressed. form.reset() restores the value attribute and the pressed toggles follow it. The group has no
disabled attribute. Disable individual toggles instead.
Accessibility
The host has role="group". Name it with aria-label. Each toggle is a button with aria-pressed. The toggles
form a native focusgroup. The arrow keys (Left and Right, or Up and Down when vertical) move focus between them,
wrapping at the ends, and Home and End jump to the first and last toggle. Space or Enter presses the focused toggle.