How to Fix Missing Form Labels — WCAG 1.3.1 Level A

Published April 30, 2026 · 8 min read · By Accessalyze

Critical violation: Missing form labels are a WCAG Level A failure — the baseline level. They are also one of the top three most commonly litigated ADA accessibility issues. Screen reader users cannot fill out a form they cannot identify.

In this guide

  1. What are missing form labels?
  2. WCAG 1.3.1: Info and Relationships
  3. Fix #1: Explicit <label> element
  4. Fix #2: aria-label attribute
  5. Fix #3: aria-labelledby
  6. Fix #4: title attribute (fallback only)
  7. Common broken patterns and their fixes
  8. Framework-specific notes
  9. How to test your fix

What Are Missing Form Labels?

A form label is the text that tells a user what to enter into a form field. Visually, labels appear as text next to or above an input — "Email address," "First name," "Password." For screen reader users, labels must be programmatically associated with their input, not just visually nearby.

A "missing form label" failure occurs when:

See how 321 websites scored →

View the 2026 Report

When a screen reader user navigates to an unlabeled input, the reader announces something like "edit text" — providing no information about what the field is for. The user is stuck.

WCAG 1.3.1: Info and Relationships

WCAG Success Criterion 1.3.1 requires that information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.

For forms, this means: if a label exists visually, that same label must be associated with the input in the HTML so assistive technologies can read it. A label that only exists as positioned text — not linked to the input — fails 1.3.1.

1.3.1 is a Level A criterion. Level A is the minimum baseline. Failing Level A violations are the first thing accessibility auditors, plaintiffs' attorneys, and automated scanners flag.

Additionally, WCAG 1.1.1 Non-text Content and 2.5.3 Label in Name can also apply to form label failures in specific contexts.

Fix #1: Explicit <label> Element (Preferred)

The most robust and universally supported method. Associate the <label> to its input using matching for and id attributes.

Before — Broken

<!-- Label and input are not associated -->
<p>Email address</p>
<input type="email" name="email" />

<!-- for/id mismatch — also broken -->
<label for="user-email">Email address</label>
<input type="email" id="email" name="email" />

After — Fixed

<label for="email">Email address</label>
<input type="email" id="email" name="email" />
Key rule: The for value on <label> must exactly match the id value on the <input>. Case-sensitive. One-to-one. Every input needs its own label.

Implicit label wrapping (also valid)

You can wrap the input inside the label element — this creates an implicit association without needing for/id:

<label>
  Email address
  <input type="email" name="email" />
</label>

This works but can be less flexible for styling. Explicit for/id association is generally preferred.

Fix #2: aria-label Attribute

Use aria-label when you cannot or do not want to add a visible text label. Common in search bars, icon buttons, or space-constrained UI.

Before — Broken

<!-- Search bar with no label -->
<input type="search" name="q" placeholder="Search…" />

After — Fixed with aria-label

<input type="search" name="q" placeholder="Search…" aria-label="Search" />
Caution: aria-label labels the field for assistive technology but remains invisible to sighted users. Use it only when a visible label is truly impossible. For WCAG 2.5.3 compliance, the aria-label text should contain the visible label text if one exists — or be descriptive if no visible text is present.

Fix #3: aria-labelledby

Use aria-labelledby to point to another element on the page whose text serves as the label. Useful when existing text (like a heading or adjacent paragraph) functionally describes the input.

Example

<h2 id="billing-heading">Billing Address</h2>

<!-- First field in the billing section uses the heading as a label -->
<input type="text" id="street" name="street"
  aria-labelledby="billing-heading street-label" />
<span id="street-label" class="visually-hidden">Street address</span>

aria-labelledby accepts multiple IDs separated by spaces — the resulting label is the concatenated text of all referenced elements. This is powerful for complex table-based forms.

Fix #4: title Attribute (Fallback Only)

The title attribute on an input will be announced by some screen readers when no other label is present. This is the weakest solution — do not rely on it as a primary fix.

<!-- Last resort only — use explicit label or aria-label instead -->
<input type="text" name="search" title="Search the site" />

The title attribute is only shown visually as a tooltip on hover. Mobile users and touch-only users will not see it at all. It is not reliable across all screen reader/browser combinations.

Common Broken Patterns and Their Fixes

Placeholder-only inputs

Placeholder text disappears when a user starts typing. It also has lower color contrast than label text. It is not a label — ever.

Broken

<input type="text" placeholder="First name" name="first_name" />

Fixed — label + placeholder

<label for="first_name">First name</label>
<input type="text" id="first_name" name="first_name" placeholder="Jane" />

Visually hidden labels (CSS display:none)

Hiding labels with display: none or visibility: hidden removes them from the accessibility tree entirely. Use the "visually hidden" pattern instead.

Broken — hidden from everyone

<label for="qty" style="display:none">Quantity</label>
<input type="number" id="qty" name="qty" />

Fixed — visually hidden but accessible

<style>
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}
</style>

<label for="qty" class="sr-only">Quantity</label>
<input type="number" id="qty" name="qty" />

Radio buttons and checkboxes

Individual radio buttons and checkboxes each need a <label>. The group needs a <fieldset> with a <legend>.

Broken

<p>Contact preference</p>
<input type="radio" name="contact" value="email" /> Email
<input type="radio" name="contact" value="phone" /> Phone

Fixed

<fieldset>
  <legend>Contact preference</legend>
  <label><input type="radio" name="contact" value="email" /> Email</label>
  <label><input type="radio" name="contact" value="phone" /> Phone</label>
</fieldset>

Select dropdowns

Select elements are often forgotten. They need labels too.

Broken

<select name="country">
  <option value="">Select country</option>
  <option value="us">United States</option>
</select>

Fixed

<label for="country">Country</label>
<select id="country" name="country">
  <option value="">Select country</option>
  <option value="us">United States</option>
</select>

Textarea

Broken

<textarea name="message" placeholder="Your message…"></textarea>

Fixed

<label for="message">Message</label>
<textarea id="message" name="message" placeholder="Your message…"></textarea>

Framework-Specific Notes

Framework / CMS Common Label Issue Fix
React / Next.js Dynamic IDs don't match for values Use useId() hook (React 18+) to generate stable, unique IDs for each label/input pair
Angular Material components don't always wire labels automatically Use Angular Material's mat-label inside mat-form-field, not a plain <label>
WordPress (Contact Form 7) Forms use [text* your-name] shortcodes that don't generate labels Add explicit label tags in the form builder or use CF7 Accessibility plugin
Shopify Theme checkout forms often have unlabeled fields Override theme form templates in sections/; add explicit <label> elements
Wix Platform-generated forms may not produce accessible markup Use Wix's native Accessibility Wizard and test with screen reader; embed custom HTML forms as a workaround for critical flows

How to Test Your Fix

After applying fixes, verify with multiple methods:

1. Automated scan

Run a free scan at accessalyze.com. Automated tools reliably catch missing label associations. If the fix is correct, the violation will disappear from your report.

2. Browser DevTools

In Chrome DevTools: open the Accessibility panel (Elements tab → Accessibility). Select the input element — check that "Name" is populated. An unlabeled input shows an empty "Name" in the accessibility tree.

3. Screen reader test

Navigate to the form with your Tab key and listen to what your screen reader announces when you land on each input:

If the screen reader says only "edit text" or "text field" without announcing the label, the fix is not working.

4. Axe browser extension

Install the free axe DevTools browser extension. Run it on your form page — any remaining label violations will be flagged with the specific element highlighted.

Scan Your Forms for Label Violations

Run a free WCAG scan on any URL. Missing form labels, ARIA errors, contrast failures, and more — instant results, no signup required.

Scan My Website Free →

Quick Reference: Which Method to Use

Situation Best Method
Standard text, email, password, tel inputs Explicit <label for>
Search bar with icon, no room for visible label aria-label
Input described by a nearby heading or paragraph aria-labelledby
Radio/checkbox group <fieldset> + <legend> + <label> per option
Select dropdown Explicit <label for>
Textarea Explicit <label for>
Icon button with no text (e.g., submit arrow) aria-label on the button

Related: Automated vs Manual Accessibility Testing · How to Fix WCAG Color Contrast · ADA Compliance for Law Firms · Run a Free Accessibility Scan

Try it yourself

Enter your website URL to get a free accessibility score.

Check your website accessibility score free Scan Now →