( Perceivable / WCAG 1.3.1 )
Form input has no label
What is this issue?
A form input, select, or textarea has no programmatic label: a label connected to its control in the underlying code (HTML/DOM), not just visually next to it. A <label for> pointing at an id is programmatic; text that merely sits beside an input with no code connection is not.
None of the three standard naming methods are present on the field: no <label for> pointing at the input’s id, no aria-label attribute, and no aria-labelledby referencing another element’s text. Assistive technology reads the DOM, not the visual layout, so a field that looks labelled on screen can still have no name in the code at all.
Why does this matter?
An unlabelled input has no accessible name: the text a screen reader announces to identify an element. It comes from the first source that applies, in order: aria-labelledby, aria-label, visible label text, then other fallbacks specific to the element type. When none of those exist, the screen reader has nothing to announce except the element’s role, like “edit text.”
For a short, low-stakes field a user might guess correctly from context. For anything that matters (a password field, a credit card number, a shipping address), a guess is a bad outcome. Users either submit the wrong data, abandon the form rather than risk a mistake, or have to explore the surrounding page structure by trial and error just to figure out what one box is asking for. Every one of those outcomes costs the business a completed form, not just an accessibility checkbox.
Who is affected?
- Screen reader users: hear only a generic role like “edit text, blank” with no indication of what to type, and have to guess from surrounding context or abandon the field.
- Voice control users: operate inputs by speaking their visible or accessible name (for example, “click Email address”); with no name to match against, the field can’t be targeted by voice at all.
- Motor impairments: lose the larger, easier-to-hit click target a connected
<label>provides, since clicking or tapping label text normally moves focus into its input for people who use a switch, head pointer, or have limited fine motor control.
What users experience
Amara uses the NVDA screen reader on her Windows laptop to fill out a signup form. She tabs to the password field and NVDA announces “edit text, blank”: nothing about it being a password field, no hint about format requirements. She has to arrow back up through the page and hope the previous line of text describes the field she just left, then Tab forward again to confirm she’s back in the right box before typing her password into a field whose name she still can’t verify.
How do I fix it?
Connect every input to a <label> element with a matching for/id pair. This is the most reliable fix because it works in every screen reader, requires no ARIA, and enlarges the input’s clickable area to include the label text, a win for mouse, touch, and motor-impaired users at the same time.
<label for="email">Email address</label>
<input type="email" id="email">
If wrapping the input inside the <label> is easier than managing a separate id, that works identically: the wrapping relationship is just as programmatic as for/id. Use aria-label only when no visible label text exists on the page at all, such as an icon-only search box, since aria-label gives assistive technology a name without showing anything to sighted users. Reach for aria-labelledby when the accessible name should reuse text that already exists elsewhere on the page, like a heading.
Code Examples
<input type="email" placeholder="Email address">
<div>Full name</div>
<input type="text">
<input type="search"><!-- Method 1: for/id pair (broadest support) -->
<label for="email">Email address</label>
<input type="email" id="email">
<!-- Method 2: wrapping label (no id management needed) -->
<label>
Full name
<input type="text">
</label>
<!-- Method 3: aria-label (only when no visible label text exists) -->
<input type="search" aria-label="Search products">The for/id pair works because the browser builds an explicit programmatic relationship between the two elements: assistive technology can look up exactly which input a label describes, and clicking the label text moves focus to the input. The wrapping method achieves the same relationship implicitly, through nesting, with no id required. aria-label skips the DOM relationship entirely and hands assistive technology a name directly, which is why it should stay a last resort rather than the default.
Framework Examples
React’s JSX uses htmlFor instead of for (a reserved word in JavaScript), and component-based forms often reuse the same input markup across many instances on one page, which means a hardcoded id like "email" collides the moment the component renders twice. React’s useId() hook generates a unique, stable id per component instance, so every rendered copy of the field keeps a working for/id pair.
import { useId, useState } from 'react';
function EmailField() {
const id = useId();
const [value, setValue] = useState('');
return (
<>
<label htmlFor={id}>Email address</label>
<input
id={id}
type="email"
value={value}
onChange={(event) => setValue(event.target.value)}
/>
</>
);
}
useId() is the framework-specific piece worth knowing: without it, a hardcoded id works fine for a one-off field but silently breaks (duplicate ids make for resolve unpredictably) the moment the same component is reused twice on one page, which is exactly when component-based UIs tend to introduce this bug.
Common Mistakes
Mistake: “The placeholder already says what the field is, so I don’t need a label.” A placeholder is not a programmatic label. It disappears the instant someone starts typing, so anyone who glances away and back has lost it, and screen reader support for reading placeholder text as a name at all is inconsistent across browsers and assistive technology. Placeholders can supplement a label with a format hint; they must never replace it.
Mistake: “The label text is right next to the input, so it must be connected.” Visual proximity does nothing for assistive technology, which reads the DOM tree, not the rendered page. A <div>Email address</div> sitting beside an <input> with no for/id pair, no wrapping, and no aria-labelledby is invisible to a screen reader as a label; it’s just unrelated text that happens to render nearby.
Mistake: “aria-label is the safest choice because it always works.” aria-label completely overrides any visible text near the input for assistive technology users, so if the visible text and the aria-label value ever drift apart, sighted and non-sighted users end up hearing different names for the same field. Prefer a real <label> whenever visible label text exists, so there’s only one piece of text to keep accurate.
Mistake: “One label element can describe a whole group of related inputs.” A <label for> only ever points at a single id. For a set of related fields (a shipping address’s street/city/postcode inputs, or a group of radio buttons), group them inside a <fieldset> with a <legend> instead of trying to stretch one <label> across all of them.
How RedFlag Detects This
Automated: axe-core rule, runs on every scan. RedFlag calls axe-core’s label rule as part of every scan, restricted to the WCAG 2.0/2.1/2.2 A and AA rule set. The rule inspects every input, select, and textarea (excluding hidden, button, and submit/reset types, which have their own naming rules) and checks whether it resolves an accessible name through any of the standard methods: a <label for>/id pair, a wrapping <label>, aria-label, aria-labelledby, or (as a last-resort fallback some browsers support) a title attribute.
False negative: axe-core confirms a name exists; it cannot judge whether that name is accurate. A <label for="email">Full name</label> pointing at an email input passes the automated check even though the label text is wrong for the field. False positive: none typical for this check, since resolving to a non-empty accessible name is a binary condition axe-core evaluates reliably. Manual step: read the announced name for every field against what the field actually collects, and confirm it matches; automated scanning can’t catch a mislabelled-but-present label.
Manual Testing
- Open the page in Chrome or Firefox with NVDA or VoiceOver running.
- Tab through every input, select, and textarea on the form.
- Listen to what’s announced immediately after the role: it should be a specific, accurate name (“Email address, edit text”), not just the role alone (“edit text, blank”) and not a generic placeholder like “Enter value here.”
- Click directly on each visible label’s text (not the input itself) and confirm focus moves into its input; this verifies the connection is programmatic, not just visual.
- Open the browser’s accessibility inspector (Chrome DevTools → Elements → Accessibility pane) on one field and confirm the “Name” property matches the visible label text.
Related WCAG Success Criteria
1.3.1 Info and Relationships: Information, structure, and relationships conveyed through presentation must also be available programmatically. A visually-proximate but disconnected label is exactly this failure: the relationship is obvious on screen but absent in the code, which is why this rule maps to 1.3.1 as its primary criterion.
4.1.2 Name, Role, Value: Every interface component must expose a name, role, and current value to assistive technology. An unlabelled input has a role (from its type) and a value (whatever’s typed into it) but no name, so it fails 4.1.2 specifically on the “name” requirement.
3.3.2 Labels or Instructions: Labels or instructions must be provided when content requires user input. This criterion is about whether a label exists at all, visible or not; a field with a programmatic-but-invisible aria-label can pass 3.3.2 while a field with visible-but-disconnected text fails both 3.3.2 and 1.3.1 at once, which is the more common real-world version of this rule.
Related Issues
Related form inputs are missing fieldset and legend covers the group-labelling case this page’s “Common Mistakes” section points to; use it whenever a single <label> isn’t enough because several inputs need one shared name.
Input only uses placeholder as its label is the single most common cause of this rule’s failures: a field that looks labelled because of its placeholder but has no programmatic label underneath it.
Form field has more than one label is the opposite failure mode: too many labels pointing at the same input instead of none, which is just as confusing for a screen reader to announce.
Form field autocomplete attribute is missing or invalid is a related but distinct requirement for the same common input types (name, email, address); labelling a field correctly doesn’t automatically make its purpose machine-identifiable for autofill.
Alt text is a raw filename and Image input is missing alt text cover the equivalent naming failure for images and image-type submit buttons: the same “no accessible name” problem, on a different element type.
References
- W3C Understanding 1.3.1: Info and Relationships
- W3C Technique H44: Using label elements to associate text labels with form controls
- MDN: The Label element
- WebAIM: Creating Accessible Forms
Frequently asked questions
Does the placeholder attribute count as a label?
No. A placeholder is not a programmatic label: it disappears the moment someone starts typing, and screen reader support for announcing it at all is inconsistent. Use a placeholder to show a format hint alongside a real label, never as a replacement for one.
Does the title attribute work as an accessible name for an input?
Technically yes, but it is the weakest option available. The title attribute only appears as a mouse-hover tooltip in most browsers, so keyboard-only and touch users never see it, and several screen readers skip it entirely. Use a visible label, aria-label, or aria-labelledby instead.
Can I visually hide a label instead of removing it?
Yes, for inputs where a visible label would be redundant, such as a single search box next to a magnifying-glass icon, use a CSS visually-hidden technique that keeps the label in the accessibility tree without displaying it on screen. Do not use display:none or visibility:hidden, since both remove the label from the accessibility tree as well as from the screen.
Does aria-label override the visible text next to an input?
Yes, completely. When aria-label is present, screen readers announce its value instead of any visible text nearby, even if the two say different things. If an input already has visible label text, connect it with a real label element or aria-labelledby instead of aria-label, so sighted and non-sighted users hear the same name.
Does one label element work for more than one input?
No. Each <label for> value must point at exactly one id, and each input should have exactly one label pointing at it. For a group of related inputs, such as a set of radio buttons, wrap the whole group in a fieldset with a legend instead of trying to share one label across them.