Checkbox
ui-checkbox renders a native <input type="checkbox"> and a <label> in its shadow root. The element's text is
the label, and clicking the label toggles the box. It is form-associated. When checked, it submits its value
(or on) under its name, like a native checkbox.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Checkbox 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/checkbox.html"></import-element>
<ui-checkbox>Accept terms and conditions</ui-checkbox>
</body>
</html>Examples
Checked
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Checkbox 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/checkbox.html"></import-element>
<ui-checkbox checked>Email me about product updates</ui-checkbox>
</body>
</html>Indeterminate
indeterminate shows a dash instead of a check mark, for a "select all" box whose items are partly checked. Like
the native property, it changes only the look. The box still submits according to checked. Clicking the box clears
indeterminate, as it does on a native checkbox.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Checkbox 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/checkbox.html"></import-element>
<ui-checkbox indeterminate>Select all</ui-checkbox>
</body>
</html>Disabled
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Checkbox 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/checkbox.html"></import-element>
<ui-checkbox disabled>Disabled</ui-checkbox>
<ui-checkbox disabled checked>Disabled and checked</ui-checkbox>
</body>
</html>Without visible text
When the checkbox has no text, name it with aria-label.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Checkbox 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/checkbox.html"></import-element>
<ui-checkbox aria-label="Select row"></ui-checkbox>
</body>
</html>Listening for changes
change bubbles from the element after each toggle. Read checked from the element.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Checkbox 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/checkbox.html"></import-element>
<import-element from="./checkbox-change-demo.html"></import-element>
<checkbox-change-demo></checkbox-change-demo>
</body>
</html><custom-element name="checkbox-change-demo">
<script>
const settings = useState({ status: "Notifications are off." });
function changed(checkbox) {
settings.status = checkbox.checked ? "Notifications are on." : "Notifications are off.";
}
</script>
<style>
:host {
display: grid;
gap: calc(var(--spacing) * 2);
}
p {
margin: 0;
font-size: var(--text-sm);
color: var(--muted-foreground);
}
</style>
<ui-checkbox onchange="changed(this)">Enable notifications</ui-checkbox>
<p role="status"><slot name="#settings.status"></slot></p>
</custom-element>In a form
Only checked boxes are submitted. Several checkboxes can share a name, and FormData.getAll() returns every checked
value. required blocks submission until the box is checked, and form.reset() restores the checked attribute.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Checkbox 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/checkbox.html"></import-element>
<import-element from="./checkbox-form-demo.html"></import-element>
<checkbox-form-demo></checkbox-form-demo>
</body>
</html><custom-element name="checkbox-form-demo">
<script>
const result = useState({ text: "Submit the form to see its data." });
function submit(event) {
event.preventDefault();
const entries = [...new FormData(event.target)].map(([name, value]) => `${name}=${value}`);
result.text = entries.join("\n") || "(nothing submitted)";
}
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);
}
.actions {
display: flex;
gap: calc(var(--spacing) * 2);
}
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-checkbox name="topics" value="releases" checked>Releases</ui-checkbox>
<ui-checkbox name="topics" value="security">Security advisories</ui-checkbox>
<ui-checkbox name="topics" value="events">Events</ui-checkbox>
<ui-checkbox name="terms" required>I agree to the terms</ui-checkbox>
<div class="actions">
<ui-button type="submit">Subscribe</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 |
|---|---|---|---|
checked |
boolean | false |
Whether the box is checked. The attribute is the initial and reset state. The property follows the user. |
value |
string | Value submitted when checked. Without it the form submits on. |
|
indeterminate |
boolean | false |
Shows the mixed state. Visual only. Cleared when the user toggles the box. |
disabled |
boolean | false |
Disables the box. Also true inside a disabled <fieldset>. |
required |
boolean | false |
The form is invalid until the box is checked. |
aria-label |
string | Accessible name when there is no visible text. Property name: label. |
The name attribute is read by the form, as on any form-associated element.
Properties
| Property | Type | Description |
|---|---|---|
checked |
boolean | Current state. Updated when the user toggles the box. Setting it updates the box and the submitted value. |
value, indeterminate, disabled, required |
Mirror the attributes above. |
Events
| Event | Detail | Description |
|---|---|---|
change |
none | Bubbles from the element after the user toggles the box. checked is already updated. |
input |
none | The native input event of the inner checkbox, which is composed and reaches the page. |
Slots
| Slot | Description |
|---|---|
| (default) | The label text. It is rendered inside a native <label> for the inner checkbox. |
CSS parts
| Part | Description |
|---|---|
control |
The inner <input type="checkbox">. |
label |
The <label> around the slotted text. |
CSS states
| State | Description |
|---|---|
:state(attr-checked) |
Set while the box is checked, for example ui-checkbox:state(attr-checked). |
Forms
ui-checkbox is form-associated. When checked it submits value, or on without one. When unchecked it submits
nothing. Validity is mirrored from the inner checkbox, so required takes part in checkValidity() and
reportValidity(). form.reset() restores the checked attribute, and a disabled <fieldset> disables the box.
Accessibility
The inner native checkbox keeps its role, Space toggles it, and the host delegates focus to it. The slotted text is
its label. When there is no text, aria-label is passed to the inner checkbox, and a <ui-label for> pointing at
the element sets one too.