HTML Guides for labelable
Learn how to identify and fix common HTML validation errors flagged by the W3C Validator — so your pages are standards-compliant and render correctly across every browser. Also check our Accessibility Guides.
A label element with a for attribute contains a form control whose id is missing or doesn't match the for value.
A label can be tied to its control in two ways: by wrapping the control, or by naming the control's id in for. When for is present, it alone picks the labeled control, and the label may not contain any other labelable element. The labelable elements are button, input (except type="hidden"), meter, output, progress, select and textarea, and the message names the one that broke the rule.
The browser follows for and ignores the nested control. If for points at an id that doesn't exist, the label has no control at all: clicking its text does nothing, and the control inside can end up without an accessible name.
A button usually gets here through a search form that wraps both the search field and its submit button in one <label for="search-field">. The field's id matches, but the button can't share it because every id in a page must be unique. The validator also reports that the label holds more than one labelable descendant, and screen readers may read the button's text as part of the field's name.
Close the label before the button, or move the button out of it, so the label holds only the control it names. When the label wraps a single control, either give that control an id equal to the for value, or remove for and let the wrapping make the association.
Invalid example
<form role="search" action="/search">
<label for="search-field">
Search for:
<input type="search" id="search-field" name="q">
<button type="submit">Search</button>
</label>
</form>
Valid example
<form role="search" action="/search">
<label for="search-field">
Search for:
<input type="search" id="search-field" name="q">
</label>
<button type="submit">Search</button>
</form>
A <label> element that wraps a form control, such as an <input> or a <select>, can't have an aria-hidden attribute, whatever its value.
aria-hidden="true" removes an element and everything inside it from the accessibility tree. When a <label> contains a labelable element (button, meter, output, progress, select, textarea, or an input of any type except hidden), hiding the label hides the control too. Keyboard users can still tab to the field, but a screen reader has nothing to announce when they get there, not even the label text that should give the control its name.
The validator reports the attribute on these labels with any value, including aria-hidden="false", so remove it instead of changing it. If the label also points to the control with a for attribute, a second error says the label is associated with a labelable element.
Remove aria-hidden from the <label>. When only part of the label is decorative, such as an icon or the asterisk that marks a required field, put aria-hidden="true" on a <span> around that part. A visually hidden CSS class keeps label text off the screen so that only screen readers read it, and aria-hidden on the same label cancels that. If the whole field has to stay hidden from everyone, as with a spam trap field, put aria-hidden="true" on an element that wraps the label and add tabindex="-1" to the control so keyboard users can't reach it.
Invalid example
<label aria-hidden="true">
Email <span class="required">*</span>
<input type="email" name="email" required>
</label>
Valid example
<label>
Email <span class="required" aria-hidden="true">*</span>
<input type="email" name="email" required>
</label>
Validate at scale.
Ship accessible websites, faster.
Automated HTML & accessibility validation for large sites. Check thousands of pages against WCAG guidelines and W3C standards in minutes, not days.
1K Weekly
1,000 monthly checks. Cancel anytime.
Get 1K Weekly →Join teams across 40+ countries