Labels (<label>)
A <label> gives a form control its accessible name — the text a screen reader announces, and
the text a sighted user reads to understand what to type. Every meaningful input should have
one. It's one of the simplest HTML elements, and one of the most frequently skipped.
Explicit Labeling: for / id
The most common and most robust pattern connects a <label> to its input using matching{' '}
for/id values.
<label for="email">Email address</label> <input type="email" id="email" name="email">
for attribute's value must exactly match the input's id — a typo silently breaks the association with no visible error.Implicit Labeling: Wrapping
Alternatively, wrap the input directly inside the <label>. No for/id pair is needed — the
association is implied by nesting.
<label> Email address <input type="email" name="email"> </label>
Pattern | Pros | Cons |
|---|---|---|
Explicit (for/id) | Flexible layout — label and input can be styled/positioned independently | Requires unique, matching ids; a typo breaks it silently |
Implicit (wrapping) | No id management needed; association can never go out of sync | Less flexible for layouts where label and input are visually separated |
for/id pattern because it plays more predictably with CSS Grid/Flexbox layouts and component libraries. Either pattern is valid HTML — pick one and be consistent.Why Labels Matter for Accessibility
Screen readers announce the label text whenever the input receives focus — without one, users hear only "edit text, blank".
Browser autofill and password managers rely partly on label text to guess a field's purpose.
Voice control software (like Voice Control on macOS/iOS) lets users say the label text to focus that field directly.
Why Labels Matter for Click-Target Size
A properly associated <label> is clickable — clicking or tapping anywhere on the label text
moves focus to (or toggles, for checkboxes/radios) its input. This dramatically increases the
effective click target, which matters most for small controls on touchscreens.
<label for="newsletter"> <input type="checkbox" id="newsletter" name="newsletter"> Subscribe to the newsletter </label> <!-- Tapping the word "Subscribe" toggles the checkbox — not just the tiny box itself -->
The Wrapping Pattern for Checkboxes and Radios
<fieldset>
<legend>Notification preferences</legend>
<label>
<input type="checkbox" name="notify" value="email">
Email me about updates
</label>
<label>
<input type="checkbox" name="notify" value="sms">
Text me about updates
</label>
</fieldset>Placeholder Is Not a Label
A common but harmful shortcut is using placeholder text instead of a real <label>. Once the
user starts typing, the placeholder disappears — and unlike a label, most placeholder text
doesn't reliably announce to screen readers as the field's name.
<!-- Bad: no real label, placeholder vanishes on input, weak accessible name --> <input type="text" name="search" placeholder="Search products..."> <!-- Good: real label (can be visually hidden), placeholder as supplementary hint --> <label for="search" class="visually-hidden">Search products</label> <input type="text" id="search" name="search" placeholder="e.g. wireless mouse">
placeholder as a replacement for <label>. If you need a visually minimal design, use a visually-hidden label (present in the DOM and to screen readers, hidden with CSS) rather than removing it entirely..visually-hidden {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}Labeling Groups of Controls
A single <label> describes one control. When several related controls form a group (a set of
radio buttons, a set of checkboxes), use <fieldset>/<legend> for the group-level label — this
is covered fully in its own page.
Key Takeaways
Every meaningful input needs a <label>, either via explicit for/id or by wrapping the input.
A correctly associated label is clickable, enlarging the effective touch target — especially valuable for checkboxes and radios.
Labels are announced by screen readers on focus; placeholder text is not a reliable substitute.
If a design calls for no visible label, use a visually-hidden label in the DOM rather than omitting it.
Use fieldset/legend, not label alone, to describe a group of related controls.