Form input labels must be visible; avoid title/aria only
Last updated:
Related Guides
Form inputs must have visible labels without relying on title or aria-describedby
A form control needs a visible label that is programmatically associated to the input.
This issue appears in text fields, selects, radios, and checkboxes when only title, placeholder, or aria-describedby is used.
It affects screen reader users, speech input users, keyboard users, and anyone who needs persistent, visible instructions.
Why It Matters
Visible labels help all users understand what a field collects and reduce mistakes. Placeholders are not persistent and disappear on focus; titles often never surface on touch devices.
Assistive technologies use the accessible name as the control’s label. aria-describedby is for additional help text, not the name. If you rely on title or aria-describedby for labeling, many users will not hear or see the correct label.
For speech input and some cognitive disabilities, the visible label needs to match the accessible name so users can say or recognize the field name reliably.
Common Causes
- Using only placeholder text as the label.
- Using the title attribute as the label.
- Using
aria-describedbyto provide the label instead of help text. - Missing or incorrect for/id pairing between label and input.
- Hiding the label visually with no persistent on-screen label alternative.
- Combining title and
aria-describedbyon the same input, creating duplicate or confusing announcements.
How to Fix
- Provide a visible text label for each input.
- Use a label element with for that matches the input id. This is the most robust pattern.
- Connect any helper or hint text with
aria-describedby.- Keep the label as the accessible name. Use
aria-describedbyonly for supplemental guidance like format, examples, or error messages.
- Keep the label as the accessible name. Use
- Avoid the title attribute for labeling.
- Many browsers and assistive technologies do not expose title consistently, especially on mobile. If legacy code uses title, remove it or ensure it does not duplicate
aria-describedby.
- Many browsers and assistive technologies do not expose title consistently, especially on mobile. If legacy code uses title, remove it or ensure it does not duplicate
- Use ARIA name only when a visible label is not possible (exceptional cases).
aria-labeloraria-labelledbycan set the accessible name, but visible text is still strongly recommended for usability.
- Ensure "label in name" when there is visible text.
- Include the same visible label text in the accessible name (benefits voice control). Example: visible label "Search" should appear in the accessible name.
- Group related controls properly.
- For radio buttons and checkboxes in a set, use fieldset and legend to provide a group label, plus individual labels for each control.
Recommendation: Prefer explicit labels over implicit labels. If you use implicit labels (wrapping input in label), verify assistive tech reads them correctly across control types and platforms.
How to Test
Keyboard
- Tab to each input. A visible label should be present and persist when the field is focused.
- The focus order should follow the visual order of labels.
Screen reader
- With NVDA/JAWS/VoiceOver, navigate to each field. Confirm the reader announces the label first, then any description from
aria-describedby. - Verify no duplicate or conflicting announcements from title.
- Check that the spoken label matches the visible label text (label in name).
Mobile/touch
- On iOS/Android with TalkBack/VoiceOver, swipe to each control. Confirm a clear label is announced without relying on hover-only title.
- Ensure labels remain visible when the on-screen keyboard opens and placeholders do not serve as the only label.
Checklist:
- Every input has a visible label adjacent to the control.
- label for matches input id;
aria-describedbypoints only to help text. - No title attribute used for labeling; do not combine title with
aria-describedby. - Accessible name equals or includes the visible label text.
- Group labels provided with fieldset and legend where needed.
Good Example
<form>
<div>
<label for="email">Email address</label>
<input id="email" name="email" type="email" aria-describedby="email-hint">
<div id="email-hint">Use a work address if possible.</div>
</div>
<fieldset>
<legend>Contact preference</legend>
<div>
<input id="pref-email" name="pref" type="radio" value="email">
<label for="pref-email">Email</label>
</div>
<div>
<input id="pref-sms" name="pref" type="radio" value="sms">
<label for="pref-sms">Text message</label>
</div>
</fieldset>
</form>Bad Example
<form>
<div>
<input id="email2" type="email" placeholder="Email" title="Enter your email" aria-describedby="e2-hint">
<small id="e2-hint">Required for receipts</small>
</div>
</form>Issues:
- No label element; placeholder disappears on focus.
- title used as a label; inconsistent on mobile and with AT.
aria-describedbyused for help, but no accessible name exists.
Quick Checklist
- Provide a visible label for every input.
- Connect labels using label for and matching input id.
- Use
aria-describedbyonly for hints, examples, or errors. - Avoid title for labeling; do not combine title with
aria-describedby. - Ensure the accessible name contains the visible label text.
- Use fieldset/legend for grouped controls.
- Do not rely on placeholder as the sole label.