Skip to Content
Component ExamplesForm Labeling

Form Labeling

The hierarchy of labeling methods — from native HTML to ARIA fallbacks

Maintained by Martin KrugerLast reviewed

Overview

Forms are one of the most common sources of accessibility failures. Screen reader users rely on properly associated labels to understand what each field expects. Without labels, a user hears only “edit text” with no context. Error messages must also be programmatically associated with the field that failed.

WCAG Criteria:

Key requirements:

  • Every input must have a <label> associated via for/id
  • Required fields must use aria-required="true" (or the required attribute)
  • Hint text should be linked via aria-describedby
  • Error messages must be associated with the invalid field via aria-describedby and aria-invalid="true"
  • Use <button type="submit">, not a <div> or <a>

Labeled Fields

Labeled Fields vs. Placeholder-Only

Inaccessible
Sign Up
View inaccessible code
<!-- Placeholders disappear when user types — no persistent label --> <input placeholder="Full name"> <input placeholder="Email address"> <div class="btn">Sign Up</div>
Accessible
We'll send a confirmation to this address.
View accessible code
<form> <div> <label for="forms-good-name">Full name</label> <input id="forms-good-name" type="text" required aria-required="true" autocomplete="name" /> </div> <div> <label for="forms-good-email">Email address</label> <input id="forms-good-email" type="email" required aria-required="true" aria-describedby="forms-good-email-hint" autocomplete="email" /> <span id="forms-good-email-hint">We'll send a confirmation to this address.</span> </div> <button type="submit">Sign Up</button> </form>

What’s wrong with placeholder-only inputs?

  • Placeholders are not visible once the user starts typing
  • Screen readers may not announce placeholder text as the field’s label
  • The <div> button is not keyboard accessible and has no button role

Predicted semantic summary (exact output varies):

VersionAnnouncement on focus
Inaccessible (placeholder)“edit text” or “blank” — no label
Accessible (label)“Full name, required, edit text”
With hint”Email address, required, edit text — We’ll send a confirmation to this address.”

Error Handling

Associated Error Messages

Inaccessible

Must be at least 8 characters.

View inaccessible code
<!-- Error text exists visually but is not linked to the field --> <label for="forms-bad-pw">Password</label> <input id="forms-bad-pw" type="password" style="border-color:red"> <p style="color:red">Must be at least 8 characters.</p>
Accessible
Error: Must be at least 8 characters.
View accessible code
<label for="forms-good-pw">Password</label> <input id="forms-good-pw" type="password" aria-invalid="true" aria-describedby="forms-pw-error" /> <span id="forms-pw-error" role="alert" style="color:red"> Must be at least 8 characters. </span>

What’s wrong without aria-invalid and aria-describedby?

  • The red border is a visual-only cue — not perceivable by screen reader users
  • The error paragraph is nearby in the DOM but not programmatically linked to the field
  • When the user focuses the input, the error is never read

Predicted semantic summary (exact output varies):

VersionAnnouncement on focus
Inaccessible”Password, edit text” — error never mentioned
Accessible”Password, invalid entry, edit text — Must be at least 8 characters.”

Labels, instructions, descriptions, and errors

A label identifies a control; it should not be overloaded with every instruction and error. Put format requirements and help in visible text and reference them with aria-describedby. Group related controls with <fieldset> and <legend>. On validation, identify the error in text, set aria-invalid="true", and associate the error with the field. A populated role="alert" in initial markup is not a reliable announcement technique; for dynamic validation, update a pre-existing alert or focus a headed error summary.

The accessible name should contain the visible label text in the same order so speech-recognition users can target what they see (WCAG 2.5.3 Label in Name). Placeholder text is an example or hint, not a persistent label.


Resources