Accessible forms: check labels and input purpose
Accessible forms explain what people need to enter and make that information available to assistive technology. A visible label, a field’s accessible name and a format instruction each do a different job.
When “Phone number” disappears as someone types, or a screen reader announces only “edit text,” people lose context. These HTML examples help you diagnose those problems in contact forms, account settings and checkouts. They cover browser-based HTML forms, not PDF forms.
What does a clearly labelled field need?
A label identifies the field’s purpose. An explicit HTML association uses the label’s for attribute to reference the field’s id. The name attribute supplies the key used in form submission; it does not replace a label. Wrapping a field inside a <label> can also associate the two. The HTML specification describes both methods.
The accessible name is the label the browser exposes to assistive technology. A separate description can explain a format requirement. WCAG 3.3.2 requires labels or instructions for input. Programmatic relationships and accessible names are also covered by 1.3.1 and 4.1.2. Having a name alone does not establish that a field is usable.
Accessible forms: six HTML cases to check
The bad and improved versions are isolated teaching examples. Test each version separately so its IDs do not collide with other examples. The results below apply to these snippets, not an entire form.
1. The field has no label
Bad: the field has an identifier in code but no name for people.
<input id="email" name="email" type="email">
Improved: a visible, associated label stays in place while someone types.
<label for="email">Email address</label>
<input id="email" name="email" type="email">
2. The label points to the wrong ID
Bad: the words appear next to the field, but for="email" has no matching element.
<label for="email">Email address</label>
<input id="contact-email" name="email" type="email">
Improved: for matches id. Clicking the label now reaches the intended field.
<label for="contact-email">Email address</label>
<input id="contact-email" name="email" type="email">
3. A reused component creates duplicate IDs
Bad: both fields use email. Both labels consequently point to the first field, leaving the second without its label association.
<label for="email">Delivery email</label>
<input id="email" name="shippingEmail" type="email">
<label for="email">Billing email</label>
<input id="email" name="billingEmail" type="email">
Improved: each instance has a unique ID. Distinct labels also explain which address belongs in each field.
<label for="shipping-email">Delivery email</label>
<input id="shipping-email" name="shippingEmail" type="email">
<label for="billing-email">Billing email</label>
<input id="billing-email" name="billingEmail" type="email">
Test reused components together on one page. A single instance will not reveal the collision. The HTML rules for for explain why the first matching ID matters.
4. A placeholder disappears during typing
Bad: the placeholder supplies all the visible labelling.
<input id="phone" name="phone" type="tel" placeholder="Phone number">
Improved: the label identifies the field permanently. An optional placeholder provides an example.
<label for="phone">Phone number</label>
<input id="phone" name="phone" type="tel" autocomplete="tel"
placeholder="e.g. +44 20 1234 5678">
In the tested browser, the bad version also had the accessible name “Phone number.” The axe label rule therefore reported no violation. Its visible label still disappeared after typing. W3C explains this drawback of placeholders. Check the field after typing and after autofill.
5. Hidden labels need the right hiding method
A compact search field can communicate its purpose through an adjacent, visible “Search” button. In that context, a visually hidden label can be appropriate. Keep visible labels for ordinary contact or address fields. W3C illustrates the search-field exception.
Bad: hidden removes the label from normal display and from this example’s accessible name.
<form role="search">
<label for="site-search" hidden>Search this website</label>
<input id="site-search" name="q" type="search">
<button type="submit">Search</button>
</form>
Improved: sr-only hides the text visually while retaining it for assistive technology. Here it means Tailwind’s existing utility, not display: none, visibility: hidden, or an arbitrary class name without CSS.
<form role="search">
<label for="site-search" class="sr-only">Search this website</label>
<input id="site-search" name="q" type="search">
<button type="submit">Search</button>
</form>
A correctly associated label usually needs no additional aria-label. That attribute can override the visible text as the name source. When the name uses different words from the visible label, speech input can also fail; see WCAG 2.5.3.
6. Autocomplete identifies input purpose
Labels help people; autocomplete makes certain input purposes machine-readable. WCAG 1.3.5 (AA) applies to information about the person using the form, where the purpose appears in the defined list and the technology supports identifying it. It does not apply indiscriminately to every text field, such as a free-text message.
Bad: firstname is not a valid autocomplete value.
<label for="given">Given name</label>
<input id="given" name="givenName" autocomplete="firstname">
Improved: given-name identifies the given name of the person completing the form.
<label for="given">Given name</label>
<input id="given" name="givenName" autocomplete="given-name">
The HTML autofill list also includes family-name, email and postal-code. Choose them according to the information requested. type="email" identifies a broad input type, but does not say whose email address it is. Whether the browser actually fills in data during a test does not determine whether 1.3.5 is met.
What did these example checks find?
We checked the HTML snippets with Chromium 149 and axe-core 4.13.0. “Passed” below means only that the specified association or property works in the example. It does not establish full WCAG conformance. Browser names came from the accessibility tree, the representation the browser exposes to assistive technology.
axe reported label for the missing label, the wrong for and the search label hidden with hidden. It reported autocomplete-valid for firstname. The improved versions cleared those findings. The corrected email fields had the browser name “Email address”; the search field had “Search this website.”
For the duplicate IDs, this axe run returned a needs-review result (incomplete) for duplicate-id-aria, rather than an automatic violation. The browser still exposed the wrong association and an unnamed second field. A needs-review result requires a separate assessment.
Omitting autocomplete entirely also produced no autocomplete-valid violation in our additional test. The rule checks supplied values; it does not decide which personal-information fields need an identifiable purpose. Review the form’s content against the W3C input purposes.
Add instructions and error messages
Instructions explain an input without replacing its label. Associate them using aria-describedby. Once validation finds an error, aria-invalid="true" exposes the invalid state. A visible message needs to explain how to correct the entry. W3C describes associating inline errors.
<label for="contact">Email address (required)</label>
<p id="contact-hint">We will reply to this address.</p>
<input id="contact" name="email" type="email" autocomplete="email"
required value="anna" aria-invalid="true" aria-describedby="contact-hint contact-error">
<p id="contact-error">Add the domain, for example name@example.org.</p>
This snippet represents an error already found by validation. Do not set the error state pre-emptively on first load; remove or update it after correction. aria-describedby supplies a description, but does not guarantee an immediate announcement whenever text changes. Test the actual flow with a screen reader. Depending on the interaction, you may need an error summary, deliberate focus management or an appropriate live region.
Try two interactive submission-feedback patterns in Making form error messages clear and accessible.
Check the complete form
- Enter values. Do labels, required-field indicators and format instructions remain clear? Check the autofilled state too.
- Click each visible label. Does it reach the correct field when the component appears more than once?
- Use Tab and Shift+Tab throughout the flow. Check visible focus, logical order and operation of every button.
- Inspect each field’s name in the browser’s accessibility tree. Compare it with the visible purpose. A name can be present and still be wrong.
- Use a screen reader to submit the form empty, completed and with invalid input. Are labels, instructions and errors understandable at the right point? Do entered values survive correction?
- Scan again after revealing additional fields and triggering validation errors. Record reached states separately from manual results.
Our browser checks of these snippets do not replace a screen-reader test of the finished form. Also check borders and selected states, text resizing and mobile layouts. For security challenges, use the pop-up and CAPTCHA guide: an arithmetic problem is not a universally accessible replacement for an image puzzle. WCAG 3.3.8 restricts cognitive function tests during authentication and defines exceptions and supporting mechanisms.
The WCAG hub’s compact label example places this work alongside other checks. Use the navable Audit to collect machine-evaluable findings and retest after corrections. Understanding the wording and completing the entire input flow still require manual testing.
