How to Fix Missing Form Labels for Accessibility
Missing form labels are one of the most common accessibility issues I find when scanning websites. They show up constantly in reports from our free scanner, and for good reason: forms without proper labels are essentially invisible to screen reader users. The input fields are there, but there's no indication of what information belongs in each one.
If you've ever run an accessibility scan and seen "Form elements must have labels" flagged, this post is for you. I'll walk you through exactly what's going wrong, why it matters, and how to fix it with specific code examples for the most common patterns.
In This Article
Why Form Labels Matter for Accessibility
Form labels exist to tell users what information a field expects. For sighted users, a well-designed form makes this obvious through visual layout. But for people using screen readers, braille displays, or voice control software, that visual context doesn't exist. They rely entirely on the programmatic connection between a <label> element and its associated <input>.
Without that connection, a screen reader user lands on a text input and hears something like "edit text, blank." That's it. No indication of whether they should type their name, email address, phone number, or credit card number. Imagine filling out a 10-field form where every single field is announced as "edit text, blank." You'd give up immediately.
Labels also matter for people with motor disabilities. When a <label> is properly associated with an input, clicking the label text focuses the input. This creates a larger click target, which is a big deal for users with tremors, limited dexterity, or anyone using a touchscreen.
From a legal perspective, missing form labels are a clear WCAG 2.2 AA violation (specifically Success Criterion 1.3.1 Info and Relationships, and 4.1.2 Name, Role, Value). They're cited frequently in ADA lawsuits because they're easy to detect and clearly block users with disabilities from completing tasks.
How Screen Readers Use Labels
When a screen reader encounters a form field, it looks for a label in a specific order of priority. Understanding this order helps you pick the right labeling technique for each situation.
First, it checks for aria-labelledby, which points to another element on the page whose text content becomes the label. Next, it looks for aria-label, an attribute directly on the input containing label text. Then it checks for a <label> element associated via the for attribute. After that, it checks if the input is nested inside a <label> element. Finally, as a last resort, it might read the title attribute or placeholder text, but support for these varies across screen readers and they're not reliable.
The most robust approach is a visible <label> element connected to the input with matching for and id attributes. This works across every screen reader, every browser, and every assistive technology. It's the approach I recommend for most form fields. For a deeper look at ARIA attributes and when to use them, check out our ARIA labels guide.
Three Ways to Label Form Inputs
There are three valid techniques for labeling form inputs. Each one is appropriate in different situations.
1. Visible Label (Best Default Choice)
A visible <label> element connected to the input with for and id. This is the gold standard. It works for everyone: sighted users see the label, screen reader users hear it, and clicking the label focuses the input.
<!-- Good: visible label with for/id connection -->
<label for="user-email">Email Address</label>
<input type="email" id="user-email" name="email">
<!-- Also good: input wrapped inside the label -->
<label>
Email Address
<input type="email" name="email">
</label>
The for/id approach is slightly more flexible because the label and input don't need to be adjacent in the DOM, but both patterns are valid.
2. Visually Hidden Label
Sometimes the visual design doesn't include a visible label. Search bars are the classic example. The magnifying glass icon and the submit button labeled "Search" make the purpose obvious to sighted users, but a screen reader still needs a label. The solution: a visually hidden <label> that's present in the DOM but invisible on screen.
<!-- Visually hidden label for a search bar -->
<label for="site-search" class="visually-hidden">Search this site</label>
<input type="search" id="site-search" name="q" placeholder="Search...">
<button type="submit">Search</button>
<!-- The CSS for visually-hidden -->
<style>
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
</style>
Don't use display: none or visibility: hidden to hide labels. Those remove the element from the accessibility tree entirely, which defeats the purpose.
3. aria-label Attribute
The aria-label attribute provides a label directly on the input without any visible text. It's the most compact option, but it has a trade-off: the label is only available to assistive technology users. Sighted users get no label at all.
<!-- aria-label on a search input -->
<input type="search" aria-label="Search this site" placeholder="Search...">
<button type="submit">Search</button>
Use aria-label sparingly. A visible label is always better when the design allows it. Reserve aria-label for cases where the visual context is genuinely sufficient (icon buttons, search bars in a clearly labeled search section) and a visible label would be redundant.
Fixing Common Patterns
Let me show you the specific fixes for the form patterns I see failing accessibility scans most often.
Search Bars
Nearly every website has a search bar, and most of them fail accessibility checks. Here's what I typically see, and how to fix it.
<!-- BAD: no label at all -->
<form>
<input type="text" placeholder="Search">
<button><img src="search-icon.svg"></button>
</form>
<!-- GOOD: visually hidden label + accessible button -->
<form role="search">
<label for="search-input" class="visually-hidden">Search</label>
<input type="search" id="search-input" placeholder="Search...">
<button type="submit" aria-label="Submit search">
<img src="search-icon.svg" alt="" aria-hidden="true">
</button>
</form>
Notice three fixes here: a visually hidden label for the input, role="search" on the form so screen readers identify it as a search landmark, and aria-label on the button so it's not announced as just "button" with no context. The icon image gets alt="" and aria-hidden="true" because the button's aria-label provides the accessible name.
Newsletter Signup Forms
These are typically a single email field with a "Subscribe" button, and they almost always rely on placeholder text instead of a real label.
<!-- BAD: placeholder as the only label -->
<form>
<input type="email" placeholder="Enter your email">
<button>Subscribe</button>
</form>
<!-- GOOD: visible label -->
<form>
<label for="newsletter-email">Email Address</label>
<input type="email" id="newsletter-email"
placeholder="[email protected]">
<button type="submit">Subscribe</button>
</form>
<!-- ALSO GOOD: visually hidden label if space is tight -->
<form>
<label for="newsletter-email" class="visually-hidden">
Email address for newsletter
</label>
<input type="email" id="newsletter-email"
placeholder="Enter your email">
<button type="submit">Subscribe</button>
</form>
Login Forms
Login forms typically have two fields (username/email and password) and often use placeholder text as labels. This is one of the worst places to skip labels, because login pages are frequently used by everyone, including people with disabilities.
<!-- BAD: no labels, just placeholders -->
<form>
<input type="email" placeholder="Email">
<input type="password" placeholder="Password">
<button>Log In</button>
</form>
<!-- GOOD: visible labels -->
<form>
<div>
<label for="login-email">Email</label>
<input type="email" id="login-email" name="email"
autocomplete="email" aria-required="true">
</div>
<div>
<label for="login-password">Password</label>
<input type="password" id="login-password" name="password"
autocomplete="current-password" aria-required="true">
</div>
<button type="submit">Log In</button>
</form>
Notice I also added autocomplete attributes. These help password managers and assistive technology identify the purpose of each field, which is a WCAG 2.2 requirement (Success Criterion 1.3.5 Identify Input Purpose).
Contact Forms
Contact forms tend to have more fields, which means more opportunities for missing labels. Here's a complete accessible contact form pattern.
<!-- GOOD: fully labeled contact form -->
<form>
<div>
<label for="contact-name">Full Name</label>
<input type="text" id="contact-name" name="name"
autocomplete="name" aria-required="true">
</div>
<div>
<label for="contact-email">Email Address</label>
<input type="email" id="contact-email" name="email"
autocomplete="email" aria-required="true">
</div>
<div>
<label for="contact-phone">Phone Number (optional)</label>
<input type="tel" id="contact-phone" name="phone"
autocomplete="tel">
</div>
<div>
<label for="contact-subject">Subject</label>
<select id="contact-subject" name="subject" aria-required="true">
<option value="">Select a topic</option>
<option value="sales">Sales inquiry</option>
<option value="support">Support request</option>
<option value="other">Other</option>
</select>
</div>
<div>
<label for="contact-message">Message</label>
<textarea id="contact-message" name="message" rows="5"
aria-required="true"></textarea>
</div>
<button type="submit">Send Message</button>
</form>
Every single field has a visible label. The optional field says "(optional)" in the label text so users know they can skip it. Required fields use aria-required="true" to communicate their status to assistive technology. For more form accessibility patterns, check out our full accessible forms guide.
Find Missing Labels on Your Site
Run a free accessibility scan to detect every missing form label, along with other WCAG issues. You'll get a detailed report with code-level fixes in under 60 seconds.
Placeholder Is NOT a Label (and Why)
This is the most common mistake I see, and it deserves its own section. Developers use placeholder text as a substitute for labels because it looks cleaner. The input says "Email Address" right inside the field, so why add a separate label element? Here's why.
Placeholders disappear when you type. Once a user starts entering text, the placeholder vanishes. Now there's no indication of what the field is for. If you're filling out a long form and need to review your entries, you can't tell which field is which. This is a problem for everyone, but especially for people with cognitive disabilities or short-term memory difficulties.
Screen reader support is inconsistent. Some screen readers read placeholder text, others don't. Even when they do, the placeholder is announced differently from a proper label. Users who rely on screen readers have learned to listen for label announcements. When a field has no label and only a placeholder, the experience is unpredictable.
Placeholder text has poor contrast. By default, placeholder text is styled in a light gray color that fails WCAG contrast requirements. If you darken the placeholder to meet contrast ratios, it looks like pre-filled text, which confuses users into thinking the field already has a value.
Placeholders aren't a substitute for instructions. If your field needs formatting hints (like "MM/DD/YYYY" for a date field), put that in helper text below the field using aria-describedby, not in the placeholder.
<!-- BAD: placeholder as the only label -->
<input type="text" placeholder="Phone (555-555-5555)">
<!-- GOOD: visible label + helper text -->
<label for="phone">Phone Number</label>
<input type="tel" id="phone" name="phone"
aria-describedby="phone-hint">
<p id="phone-hint" class="field-hint">Format: 555-555-5555</p>
You can still use placeholder text alongside a real label. That's fine. The problem is when placeholder is the only label.
Grouping Related Fields with Fieldset and Legend
Some form controls need more context than a single label can provide. Radio buttons and checkboxes are the classic example. Each individual option has its own label ("Yes" or "No"), but the user also needs to know what question is being asked.
<!-- BAD: radio buttons with no group label -->
<label><input type="radio" name="contact" value="email"> Email</label>
<label><input type="radio" name="contact" value="phone"> Phone</label>
<!-- GOOD: fieldset and legend provide the group label -->
<fieldset>
<legend>Preferred contact method</legend>
<label>
<input type="radio" name="contact" value="email"> Email
</label>
<label>
<input type="radio" name="contact" value="phone"> Phone
</label>
</fieldset>
Without the <fieldset> and <legend>, a screen reader user tabbing through these fields would hear "Email, radio button" and "Phone, radio button." They'd have no idea what they're choosing between. With the fieldset, they hear "Preferred contact method, group" followed by the individual options. That's a huge difference.
Use <fieldset> and <legend> for:
- Radio button groups
- Checkbox groups (like "Select your interests")
- Related field groups (like shipping address: street, city, state, zip)
- Yes/No questions
You might worry that <fieldset> adds an ugly border by default. It does, but a single line of CSS fixes that: fieldset { border: none; padding: 0; margin: 0; }
Testing Your Form Labels
After you've added labels to your forms, you need to verify they actually work. Here are three reliable ways to test.
Click the Label Text
The simplest test: click on the label text. If the associated input field gets focus (the cursor appears in the text field, or the checkbox toggles), your label is correctly associated. If nothing happens when you click the label, the for and id attributes don't match, or the label isn't wrapping the input.
Use Our Scanner
Run your page through our free accessibility scanner. It uses axe-core to detect form inputs without labels, inputs with duplicate IDs (which break label associations), and other form-related accessibility issues. The report will show you exactly which elements are failing and provide fix instructions.
Test with a Screen Reader
Open your page and navigate to each form field using the Tab key. Listen to what the screen reader announces. On Mac, press Cmd+F5 to turn on VoiceOver. On Windows, download NVDA (it's free) or use Narrator (built into Windows). Each field should announce its label when focused. For more on screen reader testing, see our screen reader testing guide.
Browser DevTools Inspection
In Chrome, right-click a form input and select "Inspect." In the Elements panel, look for the Accessibility section (or the "Accessibility" tab in the side panel). It shows the element's computed accessible name. If the name is empty or just says the placeholder text, the input is missing a proper label.
Firefox has a similar feature. Open DevTools, go to the Accessibility tab, and inspect the form. It will flag any inputs without accessible names.
WordPress and Shopify Fixes
WordPress Form Labels
If you're on WordPress, missing form labels usually come from your theme or form plugin. Many WordPress themes use placeholder-only inputs for search bars, login forms, and comment forms. The quickest fix is to install the WP Accessibility plugin, which can add labels to some common WordPress form patterns automatically.
For form plugins, make sure labels are enabled in the plugin settings. Contact Form 7, Gravity Forms, and WPForms all support proper labels, but you might need to turn them on or configure them correctly. We cover this in detail in our WordPress accessibility guide.
If your theme's search form lacks a label, you can override it by creating a searchform.php file in your child theme:
<!-- searchform.php in your child theme -->
<form role="search" method="get" action="<?php echo esc_url(home_url('/')); ?>">
<label for="site-search" class="screen-reader-text">Search for:</label>
<input type="search" id="site-search"
value="<?php echo get_search_query(); ?>"
name="s" placeholder="Search...">
<button type="submit">Search</button>
</form>
WordPress includes a .screen-reader-text class in most themes that works the same as the .visually-hidden pattern shown earlier.
Shopify Form Labels
Shopify themes often hide form labels with CSS for a "cleaner" look. The labels exist in the Liquid templates, but they're set to display: none, which removes them from the accessibility tree entirely. That's worse than having no label at all, because it looks intentional.
The fix is to change display: none to the visually-hidden pattern in your theme's CSS. Search your theme's stylesheet for rules that hide <label> elements and replace them:
/* BAD: removes labels from accessibility tree */
.form-label { display: none; }
/* GOOD: hides visually but keeps accessible */
.form-label {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
Pay special attention to Shopify's cart page, checkout forms, and newsletter signup sections. These are high-value interactions where missing labels directly block users from completing purchases. For more Shopify-specific fixes, see our Shopify accessibility guide.
Quick Fixes Checklist
Here's a step-by-step checklist you can work through to fix missing form labels across your site. Start at the top and work your way down.
- Run an accessibility scan to identify every form input that's missing a label. Note which pages and forms are affected.
- Add visible
<label>elements to every text input, textarea, and select menu. Use thefor/idpattern to connect them. - Add visually hidden labels to search bars and other inputs where a visible label would be redundant. Don't use
display: none. - Replace placeholder-only fields with properly labeled fields. You can keep the placeholder as a hint, but it can't be the only label.
- Wrap radio and checkbox groups in
<fieldset>and<legend>elements. Each individual option still needs its own<label>. - Add
aria-required="true"to fields that must be filled in. Don't rely on a red asterisk as the only indicator. - Add
autocompleteattributes to fields that collect personal information (name, email, phone, address, credit card). Use the standard values from the HTML spec. - Test by clicking labels. Click each label. If the associated input doesn't get focus, the
for/idconnection is broken. - Test with a screen reader. Tab through every form and listen for label announcements on each field.
- Rescan your site to confirm the issues are resolved. Fixing form labels alone can eliminate a large portion of accessibility violations.
One Common Gotcha
Make sure every id attribute is unique on the page. If two inputs share the same id, the label will only be associated with the first one. This happens more often than you'd think, especially when the same form component is rendered multiple times (like a search bar in both the header and footer). Give each instance a unique ID, like header-search and footer-search.
Missing form labels are one of the easiest accessibility issues to fix. In most cases, it's a matter of adding a few HTML elements and attributes. The fixes are straightforward, the code patterns are simple, and the impact on real users is significant. Every label you add removes a barrier for someone trying to use your website.
If you want to go deeper on accessible form patterns, read our full accessible forms guide. And if you haven't already, check out our common accessibility mistakes page to see what other issues might be lurking on your site.
Start With a Free Scan
The fastest way to find missing form labels and other accessibility issues is to run a free scan. You'll get a professional report with every issue listed, organized by severity, with code-level fix recommendations. It takes under 60 seconds.