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)
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
$12/mo · 0 missed
Card is a
<label>Good
$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.
forneeds unique ids; wrap or useuseId().