sfw/fix
label high

Form elements must have labels (missing form label)

An input has no associated label, so screen readers announce it with no name and users can't tell what to type.

What you see

Form elements must have labels
Form element does not have an implicit (wrapped) or explicit (for/id) <label>
<input type="text" name="email" placeholder="Email">

What’s actually happening

axe flags an input, select, or textarea with no accessible name. A screen reader lands on it and says "edit, blank" with no clue what the field is for. A visible placeholder doesn't rescue it — placeholders aren't labels, and they vanish the moment someone types. Sighted users also lose the bigger click target a real label provides.

Common causes

  • A placeholder used as the only field name, with no actual `<label>`.
  • A `<label>` present but its `for` attribute not matching the input's `id` (or the id is missing or duplicated).
  • Custom widgets (toggles, comboboxes) built from divs and inputs where the label was never wired up.
  • Adjacent text that looks like a label visually but isn't programmatically tied to the control.
  • Icon-only inputs like a search box that's just a magnifier glyph plus a bare field.

How to fix it

  1. Wire up an explicit label with for/idMatch them exactly: `<label for="email">Email</label><input id="email" type="email">`. Each id has to be unique on the page — duplicate ids silently break the association and axe will still flag it. This is the most robust pattern and gives a clickable label as a bonus.
  2. Or wrap the input in its labelImplicit labeling skips the id dance: `<label>Email <input type="email"></label>`. Handy in component code where ids are awkward to keep unique. The control must be a direct descendant of the `<label>`.
  3. Use aria-label or aria-labelledby when no visible label fitsFor a search field that shows only an icon: `<input type="search" aria-label="Search">`. If visible text exists elsewhere, point at it: `aria-labelledby="searchHeading"`. Reach for these only when a real `<label>` genuinely won't fit the design.
  4. Keep the placeholder as a hint, not the namePlaceholders are fine for format hints ("[email protected]") on top of a label, never instead of one. They're low-contrast, disappear on input, and aren't exposed as the accessible name. Add the label and keep the placeholder if it helps.

Stop it recurring

Add an axe or eslint-plugin-jsx-a11y check in CI so any input without a programmatic label fails the build.

Related errors