Skip to content

Checkbox

Native <input type="checkbox"> styled with .re-checkbox. Click, keyboard, and form serialization stay native.

Live example
<div class="stack">
  <label class="re-field re-field--inline">
    <input class="re-checkbox" type="checkbox" id="cb-news" name="news" />
    <span class="re-field__label">Subscribe to newsletter</span>
  </label>
  <label class="re-field re-field--inline">
    <input class="re-checkbox" type="checkbox" id="cb-default" checked />
    <span class="re-field__label">Already checked</span>
  </label>
</div>
Live example
<label class="re-field re-field--inline">
  <input class="re-checkbox" type="checkbox" id="cb-indeterminate" data-demo-indeterminate />
  <span class="re-field__label">Some children selected</span>
</label>
Please accept the terms.
Live example
<div class="stack">
  <label class="re-field re-field--inline">
    <input class="re-checkbox" type="checkbox" id="cb-disabled" disabled />
    <span class="re-field__label">Disabled</span>
  </label>
  <label class="re-field re-field--inline">
    <input
      class="re-checkbox"
      type="checkbox"
      id="cb-invalid"
      aria-invalid="true"
      aria-describedby="cb-invalid-msg"
    />
    <span class="re-field__label">Required terms</span>
  </label>
  <span id="cb-invalid-msg" class="re-validation-message">Please accept the terms.</span>
</div>
  • Keyboard — fully native. Tab moves focus to the box; Space toggles it. There’s no custom keyboard layer.
  • Focus — a visible ring shows only on :focus-visible (keyboard focus), drawn as a box-shadow plus a focus-ring border so it stays crisp at the box’s tight radius.
  • Semantics — it stays a real <input type="checkbox">, so the accessible role, checked/unchecked state, and form serialization are all native. Wrapping the input in <label class="re-field re-field--inline"> with the .re-field__label text gives an implicit label, so the text is announced as the checkbox’s name and the whole label is a click/tap target.
  • Notes — the indeterminate state is the native DOM property (el.indeterminate = true), announced as “mixed”; the dash is purely visual via :indeterminate. For validation, set aria-invalid="true" (it tints the border) and point aria-describedby at a .re-validation-message so the error is announced. The checked and indeterminate glyphs are drawn with clip-path/::before rather than an SVG asset, and a @media (forced-colors: active) block re-establishes them with system Highlight/HighlightText so checked stays distinct from unchecked in Windows High Contrast. See the accessibility guide.