Fix Form Labels for Better Accessibility
Unlabeled form fields are invisible to screen reader users. Without a label, users cannot understand what information to enter.
What's Happening
Form elements like <input>, <select>, and <textarea> need associated labels to be accessible. When a label is missing, screen readers announce the field as just "edit text" or "combo box" without context. Users cannot determine whether they should enter their name, email, or credit card number.
Diagnose
Chrome DevTools
- Open DevTools (F12)
- Go to Elements panel
- Find form elements and check for:
- Missing
<label>element nearby - Missing
forattribute matching inputid - Missing
aria-labeloraria-labelledbyattribute
- Missing
Quick console check:
document.querySelectorAll('input, select, textarea').forEach((el) => {
const hasLabel = el.labels?.length > 0
const hasAriaLabel = el.hasAttribute('aria-label')
const hasAriaLabelledby = el.hasAttribute('aria-labelledby')
if (!hasLabel && !hasAriaLabel && !hasAriaLabelledby) {
console.warn('Unlabeled form element:', el)
}
})
Accessibility Inspector
- Open DevTools > Accessibility tab
- Select the form element
- Check "Computed Properties" - the Name should not be empty
Fix
1. Use <label> with for Attribute
The explicit label association using matching for and id attributes:
<!-- Before: No label -->
<input type="email" id="email">
<!-- After: Properly labeled -->
<label for="email">Email address</label>
<input type="email" id="email">
This is the most robust method. Clicking the label focuses the input, improving usability for everyone.
2. Wrap Input in <label>
Implicit association by wrapping the input inside the label:
<!-- Implicit label - works without for/id -->
<label>
Email address
<input type="email">
</label>
This approach is simpler but less flexible for styling. Both methods are equally accessible.
3. Use aria-label for Visual Labels
When a visible label exists but isn't associated, or when the design requires no visible label:
<!-- Icon-only search button -->
<button aria-label="Search">
<svg>...</svg>
</button>
<!-- Input with visible placeholder but no label -->
<input type="search" aria-label="Search products" placeholder="Search...">
Use aria-label sparingly - visible labels are better for all users, not just screen reader users.
4. Use aria-labelledby for Complex Cases
When the label text exists elsewhere on the page:
<h2 id="contact-heading">Contact Information</h2>
<div id="phone-hint">Include country code</div>
<input
type="tel"
aria-labelledby="contact-heading phone-hint"
>
Multiple IDs can be space-separated to combine text from several elements.
Framework Examples
<template>
<UFormField label="Email address" name="email">
<UInput v-model="email" type="email" />
</UFormField>
</template>
<script setup>
const inputId = useId()
</script>
<template>
<div>
<label :for="inputId">{{ label }}</label>
<input :id="inputId" v-model="value">
</div>
</template>
htmlFor instead of for:function EmailField() {
const id = useId()
return (
<div>
<label htmlFor={id}>Email address</label>
<input id={id} type="email" />
</div>
)
}
Verify the Fix
- Re-run Lighthouse - The "Form elements have associated labels" audit should pass
- Test with screen reader - Tab to each form field and verify the label is announced
- Click test - Clicking a label should focus its associated input
Console verification:
// Should return empty array
[...document.querySelectorAll('input, select, textarea')].filter((el) => {
const hasLabel = el.labels?.length > 0
const hasAria = el.hasAttribute('aria-label') || el.hasAttribute('aria-labelledby')
return !hasLabel && !hasAria
})
Common Mistakes
- Placeholder as label — Placeholders disappear when users type. They are hints, not labels. Always provide a real label.
- Label not associated — A
<label>element near the input is not enough. Useforattribute or wrap the input inside the label. - Empty aria-label —
aria-label=""is worse than no label at all. Always provide meaningful text. - Labeling hidden inputs — Inputs with
type="hidden"should not have labels. Screen readers ignore hidden inputs. - Duplicate IDs — If two inputs share the same
id, only one gets the label. IDs must be unique per page.
Related Issues
Form label issues often appear alongside:
- Button Name — Submit buttons and form controls both need names
- Link Name — Form action links need descriptive text
- Color Contrast — Low-contrast labels are hard to read
Test Your Entire Site
Form labels are easy to miss across a large site, especially in footers, search bars, and newsletter signups that appear on every page. Unlighthouse scans your entire site and identifies every page with unlabeled form elements, helping you fix them systematically.