What's new Report an issue
GIG Cymru NHS Wales, Digital Health and Care Wales

Checkbox

A box you tick. Each option is independent — any number of them, including none.

Which one

ControlAnswersTakes effect
CheckboxAny number, including noneOn Save
RadioExactly one, all options visibleOn Save
SelectExactly one, from a longer listOn Save
SwitchOn or offImmediately

The group

A checkbox almost never appears alone. The fieldset carries the question; each label carries one answer.

Case note types

Select all that apply.

<fieldset class="sr-checkbox-group">
  <legend class="sr-checkbox-group__legend">Case note types</legend>
  <p class="sr-checkbox-group__hint">Select all that apply.</p>
  <div class="sr-checkbox-group__options">
    <div class="sr-checkbox">
      <input class="sr-checkbox__input" type="checkbox" id="n1" name="notes" checked>
      <label class="sr-checkbox__label" for="n1">General notes</label>
    </div>
  </div>
</fieldset>

States

Indeterminate is a parent state — the "Select all" box when only some children are ticked. It is never something a user can choose directly.

<!-- Rest, hover and focus come from the stylesheet. Only these four
     need markup. Indeterminate is the exception: it is a DOM property,
     not an attribute, so it cannot be set in HTML alone. -->
<div class="sr-checkbox">
  <input class="sr-checkbox__input" type="checkbox" id="c1" checked>
  <label class="sr-checkbox__label" for="c1">Checked</label>
</div>

<div class="sr-checkbox sr-checkbox--error">
  <input class="sr-checkbox__input" type="checkbox" id="c2">
  <label class="sr-checkbox__label" for="c2">Error</label>
</div>

<div class="sr-checkbox">
  <input class="sr-checkbox__input" type="checkbox" id="c3" disabled>
  <label class="sr-checkbox__label" for="c3">Disabled</label>
</div>

<script>
  // Indeterminate, set the only way it can be set.
  document.getElementById('c4').indeterminate = true;
</script>

Error

One message for the whole group, above the options, with a red rule down the left. Never a message per option.

Case note types

Select at least one note type

Long labels

A label that runs past the line wraps under itself, not under the box. The label is an inline-block with left padding rather than a flex sibling, which is what keeps the second line aligned with the first. Do not switch it to flex to "fix" the indent.

Consent

A box you tick. Use it when each option is independent, "any of these, including none".


When to use

When not to use

How it works

Do & don't

DoDon't
Write labels as the answer, "Include discharged patients"Write labels as the question, "Discharged?"
Put the most common option firstOrder options alphabetically when frequency is known
Use one group per questionPut two questions in one fieldset
Let a long label wrapTruncate a label with an ellipsis
Keep "Select all" adjacent to the list it selectsUse indeterminate as a user-selectable state

Accessibility

, hideLegend hides them visually only.

Known gaps

Accessibility requirements

RequirementWCAG SCHow Single Record meets itTest method
Group name is announced with each option1.3.1, 4.1.2A real fieldset and legend, so "Case note types, General notes, checkbox" is announced rather than a bare label. hideLegend hides it visually only.Screen reader announce
Each option has a programmatic label1.3.1A real label element bound to the input, so clicking the text toggles the box and the name reaches assistive technology.Screen reader, click the label
Mixed state is exposed4.1.2indeterminate is set as a DOM property, which the browser exposes as aria-checked="mixed".Screen reader, partial select-all
State is not colour alone1.4.1The box fills and gains a tick; the border darkens. All three change together, so the state survives greyscale.Greyscale review
Error is exposed and actionable3.3.1, 3.3.3The message is referenced from the group and says what to do ("Select at least one note type"), not what went wrong.Screen reader, submit empty
Required state is more than an asterisk3.3.2The asterisk is decorative; the group carries aria-required.Screen reader announce
Target size2.5.8The 20px box relies on the spacing exception: 12px between options puts centres 32px apart. The clickable label extends the target further. Tightening the gap breaks this.Measure spacing
Keyboard operable2.1.1Native input: Tab between options, Space to toggle. No custom key handling.Keyboard only
Focus visible2.4.7A 3px Cyan/700 ring on the box alone, so it is not stretched around a long label.Keyboard tab