label critical
Form input has no associated label (WCAG 4.1.2)
An input, select, or textarea has no programmatic label, so screen readers can't tell users what to type into it.
What you see
axe-core: Form elements must have labels (label) — Critical
Fix any of the following:
Element does not have an implicit (wrapped) <label>
Element does not have an explicit <label>
aria-label attribute does not exist or is empty
Lighthouse: Form elements do not have associated labels What’s actually happening
A sighted visitor sees a box and a bit of placeholder text and knows what to do. A screen reader user gets "edit text, blank" and nothing else — no field name, no purpose. The control still works with a mouse, which is exactly why this ships to production unnoticed: it looks fine on screen and breaks only for assistive tech and voice control. Search and contact forms are the usual offenders, and a search box nobody can fill out is a search box that loses you the lead.
Common causes
- A styled placeholder is doing the job of a label — placeholders vanish on focus and are ignored by many screen readers
- A visible <label> exists but its for attribute doesn't match the input's id (typo, duplicated id, or no id at all)
- An icon-only field (a magnifying-glass search box) has no text and no aria-label
- A custom component renders a bare <input> with the label text sitting in a separate <div> that's never wired to it
- A select or textarea was added later and skipped the labelling pattern the rest of the form uses
How to fix it
- Wire a real <label> to the inputGive the input an id and point a <label for> at it: <label for="email">Email</label><input id="email">. The id must be unique on the page — a duplicated id silently breaks the association even though the markup looks right. Clicking the label should focus the field; if it does, the link is correct.
- If the label has to be visually hidden, keep it in the DOMFor a search box where design forbids a visible label, don't delete it — hide it with a visually-hidden / sr-only class (clip, not display:none, which removes it from the accessibility tree). The label stays available to screen readers while staying invisible on screen.
- Use aria-label or aria-labelledby when no text element existsFor an icon-only control, add aria-label="Search" directly on the input. If there's already visible text elsewhere that names the field, reference it by id with aria-labelledby instead of duplicating the string. Don't rely on placeholder or title — axe ignores both for this rule, and so do most screen readers.
- Stop treating placeholder as a labelPlaceholder text is a hint, not a name. Keep it if you like, but it cannot be the only thing identifying the field. Pair every placeholder with a real label using one of the methods above.
- Re-run the checker on the rendered pageOpen DevTools, run the axe or Lighthouse accessibility audit again, and confirm the label / "Form elements do not have associated labels" item is gone. Check the rendered DOM, not the template — framework hydration sometimes strips the for/id pairing you wrote.
Stop it recurring
Add an axe-core check to CI (jest-axe, cypress-axe, or Playwright's @axe-core/playwright) so an unlabelled field fails the build instead of reaching a user.
Related errors