Checkbox
A checkbox lets people select one or more items from a list, or turn one item on or off in a form that is saved later. It is selected, unselected or indeterminate (a parent whose children are partly selected), and any of them in error. For a setting that takes effect at once, use a switch. See the M3 checkbox guidelines.
Usage
import { createCheckbox } from 'mtrl';
const checkbox = createCheckbox({ label: 'I accept the terms', name: 'terms' });
checkbox.on('change', ({ checked }) => acceptTerms(checked));
document.body.append(checkbox.element);
<m-checkbox name="terms">I accept the terms</m-checkbox>
<script type="module">
const checkbox = document.querySelector('m-checkbox');
checkbox.addEventListener('change', (event) => acceptTerms(event.detail.checked));
</script>
import { Checkbox } from 'mtrl/react';
import { acceptTerms } from './app';
export function Example() {
return (
<Checkbox onChange={(event) => acceptTerms(event.detail.checked)} name="terms">I accept the terms</Checkbox>
);
}
<script setup lang="ts">
import { MCheckbox } from 'mtrl/vue';
import { acceptTerms } from './app';
</script>
<template>
<MCheckbox @change="acceptTerms($event.detail.checked)" name="terms">I accept the terms</MCheckbox>
</template>
<script lang="ts">
import { Checkbox } from 'mtrl/svelte';
import { acceptTerms } from './app';
</script>
<Checkbox onchange={(event) => acceptTerms(event.detail.checked)} name="terms">I accept the terms</Checkbox>
import { Checkbox } from 'mtrl/solid';
import { acceptTerms } from './app';
export function Example() {
return (
<Checkbox onChange={(event) => acceptTerms(event.detail.checked)} name="terms">I accept the terms</Checkbox>
);
}
Examples
Indeterminate
A parent checkbox is indeterminate while some of its children are selected. Checking it
selects every child, unchecking it clears them; keep it unchecked while indeterminate, so a
click checks everything. Its children are the app's to keep in step: check(), uncheck() and
setValue() clear the indeterminate state, and emit change when the state changes, without
the nativeEvent a user's click carries.
import { createCheckbox } from 'mtrl';
const checkbox = createCheckbox({ label: 'Additions', indeterminate: true });
document.body.append(checkbox.element);
<m-checkbox>Additions</m-checkbox>
<script type="module">
const checkbox = document.querySelector('m-checkbox');
checkbox.indeterminate = true;
</script>
import { Checkbox } from 'mtrl/react';
export function Example() {
return (
<Checkbox indeterminate>Additions</Checkbox>
);
}
<script setup lang="ts">
import { MCheckbox } from 'mtrl/vue';
</script>
<template>
<MCheckbox indeterminate>Additions</MCheckbox>
</template>
<script lang="ts">
import { Checkbox } from 'mtrl/svelte';
</script>
<Checkbox indeterminate>Additions</Checkbox>
import { Checkbox } from 'mtrl/solid';
export function Example() {
return (
<Checkbox indeterminate>Additions</Checkbox>
);
}
Required, in error
error draws the error colors and sets aria-invalid; set it when a required checkbox is left
unselected.
import { createCheckbox } from 'mtrl';
const checkbox = createCheckbox({ label: 'Share usage data', required: true, error: true });
document.body.append(checkbox.element);
function clearError() {
checkbox.setError(false);
}
<m-checkbox required error>Share usage data</m-checkbox>
<script type="module">
const checkbox = document.querySelector('m-checkbox');
function clearError() {
checkbox.toggleAttribute('error', false);
}
</script>
import { useState } from 'react';
import { Checkbox } from 'mtrl/react';
export function Example() {
const [error, setError] = useState(true);
const clearError = () => setError(false);
return (
<Checkbox required error={error}>Share usage data</Checkbox>
);
}
<script setup lang="ts">
import { ref } from 'vue';
import { MCheckbox } from 'mtrl/vue';
const error = ref(true);
function clearError() {
error.value = false;
}
</script>
<template>
<MCheckbox required :error="error">Share usage data</MCheckbox>
</template>
<script lang="ts">
import { Checkbox } from 'mtrl/svelte';
let error = $state(true);
function clearError() {
error = false;
}
</script>
<Checkbox required error={error}>Share usage data</Checkbox>
import { createSignal } from 'solid-js';
import { Checkbox } from 'mtrl/solid';
export function Example() {
const [error, setError] = createSignal(true);
const clearError = () => setError(false);
return (
<Checkbox required error={error()}>Share usage data</Checkbox>
);
}
A parent with its children, from the M3 guidelines, is planned for Examples.
API
Options
| Option | Type | Default | Description |
|---|---|---|---|
label |
string |
undefined |
The label, which names the checkbox; a click on it toggles too |
labelPosition |
'start' | 'end' |
'end' |
Which side of the box the label sits on, in the reading direction |
checked |
boolean |
false |
Whether it starts selected |
indeterminate |
boolean |
false |
Whether it starts indeterminate |
error |
boolean |
false |
The error state: error outline, container and state layers, and aria-invalid |
disabled |
boolean |
false |
Whether it starts disabled |
name |
string |
undefined |
The input's name, for forms |
value |
string |
'on' |
The value submitted when selected |
required |
boolean |
false |
Whether the form requires it selected |
ariaLabel |
string |
undefined |
Accessible name when there is no visible label |
class |
string |
undefined |
Additional CSS classes |
prefix |
string |
'mtrl' |
Prefix for CSS class names |
variant |
string |
undefined |
Deprecated, no effect: M3 has one checkbox |
Methods
| Method | Parameters | Returns | Description |
|---|---|---|---|
check() / uncheck() / toggle() |
none | CheckboxComponent |
Changes the state, clears indeterminate, and emits change when the state changes |
isChecked() |
none | boolean |
Whether it is selected |
setIndeterminate(state) |
state: boolean |
CheckboxComponent |
Sets or clears the indeterminate state |
setError(error) |
error: boolean |
CheckboxComponent |
Sets or clears the error state |
getValue() |
none | boolean |
The selected state |
setValue(value) |
value: boolean | string |
CheckboxComponent |
Selects or clears it; the strings 'true' and '1' select |
getValueAttribute() / setValueAttribute(value) |
value: string |
string / CheckboxComponent |
The input's value attribute |
getLabel() / setLabel(text) |
text: string |
string / CheckboxComponent |
The label |
enable() / disable() |
none | CheckboxComponent |
The disabled state |
on(event, handler) / off(event, handler) |
event: 'change', handler: Function |
CheckboxComponent |
Adds or removes a listener |
destroy() |
none | void |
Removes the checkbox |
Events
| Event | Description | Data |
|---|---|---|
change |
The state changed | { checked, value, nativeEvent? } |
nativeEvent is there when the user toggled it, not for the methods. The web component's
change carries { checked, value }.
Accessibility
- A native checkbox, named by its label, or by
ariaLabelwithout one. - Indeterminate reaches assistive tech as "mixed"; error as
aria-invalid. Tabfocuses it andSpacetoggles it.Enteris left to the form, which it submits, as with a native checkbox.- Keyboard focus draws a 0.10 state layer and a 3dp focus ring; a pointer shows no ring.
- The whole 48dp target and the label toggle it.
Styling
.mtrl-checkbox { } /* the root */
.mtrl-checkbox--indeterminate, .mtrl-checkbox--error, .mtrl-checkbox--disabled { }
.mtrl-checkbox--label-start, .mtrl-checkbox--label-end { }
.mtrl-checkbox__input { } /* the native input, over the whole checkbox */
.mtrl-checkbox__icon { } /* the box; ::before is the state layer, ::after the dash */
.mtrl-checkbox__label { }
Measurements
From the m3.material.io checkbox specs, then Compose's CheckboxTokens and material-web.
| Attribute | Value |
|---|---|
| Box | 18dp, 2dp corner, 2dp outline |
| Unselected | No fill, on-surface-variant outline (on-surface on hover, focus and press) |
| Selected and indeterminate | primary container, on-primary check or dash |
| Error | error outline and container, on-error check |
| Disabled | on-surface 38% outline or container, surface check and dash |
| State layer | 40dp circle: on-surface when unselected, primary when selected; a press takes the color of the state it leads to |
| Touch target | 48dp |
| Label | Body Large, on-surface, 12dp from the box |
| Motion | The check draws in on the default spatial spring and leaves at once |