Associate every form control with an explicit label
Canonical URL: https://devexamples.com/html/label-form-controls-with-the-for-attribute/
The problem
A form renders fine and looks self-explanatory, but its controls are announced as 'edit text' or 'combo box', and the hint text that makes each field obvious is only decoration. The field order must stay flexible in CSS, and the submitted payload must be unchanged. Current browsers and their bundled screen readers are assumed.
Short answer
Give each control a unique id and a name, point a label at that id with for, keep the visible label text inside the label, and move help text to aria-describedby rather than into the label itself.
A control’s accessible name is what a screen reader says when focus arrives, what a voice-control user says to reach it, and what an error message refers to. In HTML that name comes from a label, and the association is carried by two attributes that have to match.
<form class="signup">
<div class="field">
<label for="email">Email address</label>
<input
id="email"
name="email"
type="email"
autocomplete="email"
required
aria-describedby="email-hint"
>
<p id="email-hint" class="hint">Used for receipts only.</p>
</div>
<div class="field">
<label for="region">Region</label>
<select id="region" name="region" required>
<option value="">Select a region</option>
<option value="eu">European Union</option>
<option value="uk">United Kingdom</option>
</select>
</div>
<button type="submit">Create account</button>
</form>The same association can be made by wrapping instead of pointing, which is the only case where a for attribute is genuinely optional.
<label class="consent">
<input type="checkbox" name="marketing" value="digest">
<span>Send me the monthly digest</span>
<small>About 400 words, no attachments.</small>
</label>When there is no room for visible text, the label still has to exist in the accessibility tree.
<form class="site-search">
<label class="visually-hidden" for="q">Search examples</label>
<input id="q" name="q" type="search">
<button type="submit">Search</button>
</form>.visually-hidden {
position: absolute;
inline-size: 1px;
block-size: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.field {
display: grid;
gap: 0.25rem;
margin-block-end: 1rem;
}Explanation
A label with for="email" and an input with id="email" create a labelled-control relationship in the HTML parser, not a styling coincidence: the label’s descendant text becomes that control’s accessible name in the accname computation, and the association also means activating the label focuses or toggles the control. That second half is a real interaction gain, because the label is usually far wider than the checkbox or radio it names, so the activation area a reader has to aim at comfortably exceeds the 24 by 24 CSS pixels that WCAG 2.2 SC 2.5.8 describes. Explicit pairing is preferred over the wrapping form because it decouples the name from the position: the two can be siblings in a grid container, in different visual order, or even separated by other content, and the relationship survives. It also keeps the name clean, since a wrapping label takes its name from all of its text content, including the <small> aside in the second block, so that consent checkbox is announced as “Send me the monthly digest, about 400 words, no attachments” rather than the shorter phrase a reader would choose.
The hint text is deliberately outside the label and pulled in with aria-describedby. Labels answer “what is this”; descriptions answer “what should I know about it”, and merging them into the name makes every repeat of the field announce a paragraph. Descriptions are announced after the name and can be updated independently, which is also where a validation message belongs when the field has one. The required attribute is a state, not a name, so it needs a visible marker as well; the marker should be text inside the label or the instructions, because a red asterisk alone is colour-only signalling and fails SC 1.4.1 Use of Color for anyone who cannot see red.
Three boundaries are worth checking on your own form. More than one label may point at the same control, and their text is concatenated into one name, which is occasionally the intended answer and occasionally a mouthful. Buttons, links and other controls with their own content are not labelled this way: a label pointing at a button does not replace the text inside it, so an icon-only button takes a text alternative on the button itself rather than a label. And the association is not part of submission: id is for the label and script, name is what the browser sends, so a control that got an id but never a name looks complete, is announced correctly, and silently contributes nothing to the payload.
Usage notes
- The for and id values have to match exactly, including case, and the id must be unique in the document; a duplicated id leaves the second control unnamed.
- Only labelable elements accept a labeled control, which covers input, select, textarea, button, meter, output and progress, but not a span standing in for one.
- A visually hidden label is the right tool when the design omits the text, not when the text is merely inconvenient.
Common mistakes
- Using placeholder text as the field name, which disappears as soon as the reader types and is only a fallback name at best.
- Adding aria-label on a control that already has a visible label, so the spoken name and the seen name disagree.
- Giving the control an id but no name, which keeps the label working while leaving the field out of the submitted form.
Follow-up
Follow-up
Group related checkboxes with a fieldset and legendOnce each control is named, group the related ones under a legend.
Related examples
Editorial links first, then deterministic same-task or same-topic candidates. Tags and shared language alone never qualify a candidate.
Related
Validate form input before the browser submits itA validation message can only name the control this association makes known.
Same task or topic
Group related checkboxes with a fieldset and legendSolves the Author accessible form markup task
Same task or topic
Announce field errors without moving the caretShares the Form Validation topic
References
- The label element - HTML Living Standard(opens in a new tab) — WHATWG. Defines the labeled control, the for attribute and the list of labelable elements.
- Accessible Name and Description: Computation and API Mappings 1.2(opens in a new tab) — W3C. The label step in accessible name computation, including concatenated labels.
- Success Criterion 3.3.2 Labels or Instructions(opens in a new tab) — W3C. The AA requirement for labels or instructions when content expects user input.
Source page: https://devexamples.com/html/label-form-controls-with-the-for-attribute/