Button Group
ui-button-group lays its children out in a row or column and removes the inner corner radii, so neighbouring
ui-button (or ui-toggle) elements read as one control. The host has the group role. It only handles layout
and does not track a value. For a group of pressable buttons with a selected value, use
Toggle Group.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Button 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-group.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/button.html"></import-element>
<ui-button-group aria-label="Text alignment">
<ui-button variant="outline">Left</ui-button>
<ui-button variant="outline">Center</ui-button>
<ui-button variant="outline">Right</ui-button>
</ui-button-group>
</body>
</html>Examples
Icon buttons
Group icon buttons for toolbars. Each icon button needs its own aria-label.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Button 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-group.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/button.html"></import-element>
<ui-button-group aria-label="History">
<ui-button variant="outline" size="icon" aria-label="Undo">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M9 14 4 9l5-5" /><path d="M4 9h11a5 5 0 0 1 0 10h-4" /></svg>
</ui-button>
<ui-button variant="outline" size="icon" aria-label="Redo">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m15 14 5-5-5-5" /><path d="M20 9H9a5 5 0 0 0 0 10h4" /></svg>
</ui-button>
</ui-button-group>
</body>
</html>Split button
A primary action next to a second button that opens more options.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Button 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-group.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/button.html"></import-element>
<ui-button-group aria-label="Merge">
<ui-button>Merge pull request</ui-button>
<ui-button size="icon" aria-label="More merge options" popovertarget="button-group-menu">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>
</ui-button>
</ui-button-group>
<div id="button-group-menu" popover>Squash and merge, or rebase and merge.</div>
</body>
</html>Separator
Buttons with a filled background have no border between them. Put a ui-button-group-separator between them to
draw one.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Button 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-group.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/button.html"></import-element>
<ui-button-group aria-label="Copy and share">
<ui-button variant="secondary" size="sm">Copy</ui-button>
<ui-button-group-separator></ui-button-group-separator>
<ui-button variant="secondary" size="sm">Paste</ui-button>
</ui-button-group>
</body>
</html>Text
ui-button-group-text adds a bordered label to the group, joined like the buttons.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Button 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-group.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/button.html"></import-element>
<ui-button-group aria-label="Zoom">
<ui-button variant="outline" size="icon" aria-label="Zoom out">−</ui-button>
<ui-button-group-text>100%</ui-button-group-text>
<ui-button variant="outline" size="icon" aria-label="Zoom in">+</ui-button>
</ui-button-group>
</body>
</html>Vertical
orientation="vertical" stacks the buttons and joins the top and bottom corners. A separator in a vertical group
takes orientation="horizontal".
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Button 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-group.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/button.html"></import-element>
<ui-button-group orientation="vertical" aria-label="Volume">
<ui-button variant="secondary" size="icon" aria-label="Louder">+</ui-button>
<ui-button-group-separator orientation="horizontal"></ui-button-group-separator>
<ui-button variant="secondary" size="icon" aria-label="Quieter">−</ui-button>
</ui-button-group>
</body>
</html>Form actions
Grouped buttons keep their form behaviour, so a group can hold the submit and reset actions of a form.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Button 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-group.html"></import-element>
<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/input.html"></import-element>
<import-element from="./button-group-form-demo.html"></import-element>
<button-group-form-demo></button-group-form-demo>
</body>
</html><custom-element name="button-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);
}
output {
display: block;
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-input name="query" value="button group" aria-label="Search"></ui-input>
<ui-button-group aria-label="Search actions">
<ui-button type="submit">Search</ui-button>
<ui-button type="reset" variant="outline">Clear</ui-button>
</ui-button-group>
</form>
<output><slot name="#result.text"></slot></output>
</custom-element>API
Parts
| Element | Fills | Renders |
|---|---|---|
ui-button-group |
A role="group" row or column that joins its children's corners. |
|
ui-button-group-text |
the default slot of ui-button-group |
A bordered, muted label joined like a button. |
ui-button-group-separator |
the default slot of ui-button-group |
A one-pixel role="separator" line between two buttons. |
Attributes
ui-button-group
| Attribute | Type | Default | Description |
|---|---|---|---|
orientation |
"horizontal" | "vertical" |
"horizontal" |
Lays the children out in a row or a column. |
ui-button-group-separator
| Attribute | Type | Default | Description |
|---|---|---|---|
orientation |
"vertical" | "horizontal" |
"vertical" |
Direction of the line. Use "horizontal" in a vertical group. Sets aria-orientation. |
Slots
| Slot | Description |
|---|---|
| (default) | The grouped buttons. Every child except the first gets --ui-radius-start: 0 and a -1px start margin so borders overlap. Every child except the last gets --ui-radius-end: 0. |
CSS states and custom properties
| Name | Description |
|---|---|
:state(attr-orientation-is-vertical) |
Set when orientation="vertical". |
The group sets --ui-radius-start and --ui-radius-end on its children. ui-button, ui-toggle and
ui-button-group-text read them. Other children can use them for their own corner radii.
Accessibility
The host has role="group". Give it an aria-label that names what the buttons do together.