A small native well that fills with ink when checked.
On this page
A checkbox is a small well that fills with ink when checked. Put .checkbox on a native <input type="checkbox">, and wrap it with its text in a <label class="check"> so the whole row is a target. Each checkbox is its own yes or no; for one choice among several, use a radio.
Checkbox
<labelclass="check"><inputtype="checkbox"class="checkbox"checked>Email me about releases</label><labelclass="check"><inputtype="checkbox"class="checkbox">Weekly digest</label>
The box centers on the first line of its label and stays there when the label wraps, so a sentence can follow it.
Long labels
<labelclass="check max-w(320)"><inputtype="checkbox"class="checkbox"required>I have read the terms of service and understand that deployments on the free plan pause after 30 days without traffic.</label>
When an option needs a title and a description of its own, use a choice.
A disabled checkbox fades, and its label drops to disabled ink.
Disabled
<labelclass="check"><inputtype="checkbox"class="checkbox"checkeddisabled>Required by your plan</label><labelclass="check"><inputtype="checkbox"class="checkbox"disabled>Not available in your region</label>
A checkbox is a square with a chip's corner, which says "any of these". Where the browser draws continuous corners, that square takes the shape of an app icon. The check arrives with a short settle and leaves at once; with reduced motion it only fades.
/* * Checkbox: a native input drawn as a small well that fills with ink when checked. * Its corner is a chip's, so with continuous corners it takes the shape of an app icon. * Wrap it with its text in a .check label to make the whole row a target; the same label * serves a radio and a switch. */@layer components {.check{display:inline-flex;align-items:flex-start;gap:.5rem;color:var(--color-text-strong);font-size:.875rem;line-height:1.45;cursor:pointer;touch-action:manipulation;-webkit-tap-highlight-color:transparent;&:has(.checkbox:disabled,.radio:disabled,.switch:disabled){color:var(--color-text-disabled);cursor:not-allowed;}/* On touch the label is the target: it reaches 44px around its line without moving what stands near it. */@media(pointer:coarse){padding-block:.75rem;margin-block:-.75rem;}}.checkbox{--check-size:1.125rem;position:relative;display:inline-grid;flex:none;place-items:center;width:var(--check-size);height:var(--check-size);/* Centres the control on the first line of a label that wraps. */margin:max(0px,calc((1lh -var(--check-size))/2))0;padding:0;border:0;border-radius:calc((var(--radius-chip)-1px)*var(--corner-scale));corner-shape:var(--corner-shape);background:var(--color-surface-inset);/* A small control needs a firmer edge than a surface to be found: one step, still half a pixel. */box-shadow:var(--shadow-pressed),inset000.5pxvar(--color-line-strong);vertical-align:middle;appearance:none;cursor:inherit;transition-property: background-color, box-shadow;transition-duration:var(--duration-quick);transition-timing-function:var(--easing-glide);&::after{content:'';width:10px;height:10px;opacity:0;scale:.6;background:var(--color-text-inverse);/* The mark leaves at once and arrives with a short settle. */transition: opacity var(--duration-press)linear, scale var(--duration-press)linear;}@media(hover:hover){&:hover:not(:checked,:indeterminate,:disabled){background:var(--color-surface-inset-hover);box-shadow:var(--shadow-pressed),inset000.5pxvar(--color-text-muted);}}&:is(:checked,:indeterminate){background:var(--color-surface-inverse);box-shadow:var(--shadow-ink-mark);&::after{opacity:1;scale:1;transition: opacity var(--duration-quick)var(--easing-glide), scale var(--duration-base)var(--easing-glide);}}&:focus-visible{@apply--focus-ring;}&:disabled{opacity:.5;}@media(prefers-reduced-motion:reduce){&::after{scale:1;}}/* Draw with system colors so the mark survives forced colors. */@media(forced-colors:active){forced-color-adjust:none;background: Field;box-shadow:inset0001px FieldText;&::after{background: HighlightText;}&:is(:checked,:indeterminate){background: Highlight;box-shadow:none;}&:disabled{opacity:1;box-shadow:inset0001px GrayText;}&:focus-visible{outline-color: Highlight;}}}.checkbox::after{mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M2 5.2 4.1 7.3 8 2.8' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")center/containno-repeat;}.checkbox:indeterminate::after{mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M2.5 5h5' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E")center/containno-repeat;}}