A <label> wrapping
<input type="checkbox"> is the control. The
label text is a sibling of the input — no extra class, no
required <span>. They are CSS only. There is
no JavaScript component and nothing to AutoInit.
Tokens follow the
M3 checkbox spec.
The container is 18dp with 2dp corners. Unselected is a 2dp
on-surface-variant outline. Selected is a
primary fill with an on-primary
check. Indeterminate is the same fill with a dash. The state
layer is 40dp at 8% hover and 10% focus. The touch target is
48dp. The label is body-large /
on-surface. Disabled is 38%.
Put the input first. Add checked or
disabled on the input. Indeterminate is not an
HTML attribute — set element.indeterminate = true
in script. filled-in is a no-op: the selected
state is always the filled box.
<label>
<input type="checkbox">
Red
</label>
<label>
<input type="checkbox" checked>
Yellow
</label>
<label>
<input type="checkbox" disabled>
Brown
</label>
document.getElementById('indeterminate-checkbox').indeterminate = true;
An input + span still works if you already have
that markup, or if you follow BeerCSS’s
<label class="checkbox"> pattern. Multiple
<select> still emits
input + span that way.
<label class="checkbox">
<input type="checkbox">
<span>Yellow</span>
</label>
In a row
Put the labels in a <div class="inline"> to sit them on one
line. A bare group stacks vertically.
<div class="inline">
<label>
<input type="checkbox" checked>
Red
</label>
<label>
<input type="checkbox">
Yellow
</label>
</div>
Error
Add aria-invalid="true" or
class="invalid" on the input. The box uses
error / on-error.
<label>
<input type="checkbox" aria-invalid="true">
Accept the terms
</label>