Make labels clickable

A checkbox or radio should share one hit target with its label.

Web Interface Guidelinesvercel-labs · command.md
Labels clickable (`htmlFor` or wrapping control) Checkboxes/radios: label + control share single hit target (no dead zones)
Rules, Forms sectionView source ↗

From web-design-guidelines (Web Interface Guidelines).

Notification settings

Click the words, not the boxes.

Box is the targetBad
<input aria-labelledby><span> 0 missed
Row is the targetGood
<label><input> text</label> 0 missed
<label class="row">
  <input type="checkbox" name="paid">
  <span>Invoice paid</span>
</label>

.row { display: flex; align-items: center; gap: 12px;
       min-height: 44px; padding: 10px 12px; cursor: pointer; }

Billing: Monthly or Annual

Click the word “Annual” or its price.

Card is a <div>Bad
Billing, bad version
Monthly$12 / month
Annual$120 / year · save 17%
$12/mo · 0 missed
Card is a <label>Good
Billing, good version
$12/mo · 0 missed
<fieldset>
  <legend>Billing</legend>
  <label class="plan">
    <input type="radio" name="billing" value="annual">
    <b>Annual</b> <span>$120 / year</span>
  </label>
</fieldset>

.plan:has(:checked) { border-color: var(--accent); }

Click the label, then type

Click “Work email”, then type without clicking the field.

Text above the fieldBad
Work email
0 lost
<label for>Good
0 lost
<label for="email">Work email</label>
<input id="email" type="email" autocomplete="email">

const id = useId();
<label htmlFor={id}>Work email</label><input id={id} />

Why it matters, pros and cons

Why it matters

People aim at the words, not a 16px square.

Pros

  • Target grows from 16px to the row.
  • The label becomes the accessible name.
  • Native: no JS, works with touch and keyboard.

Cons

  • Never nest links in a label; the click also toggles.
  • Rows with other actions should not be one label.
  • for needs unique ids; wrap or use useId().