Himanshu SharmaSoftware engineer
Let’s talk

HTML · Lesson 24 of 31

Labels and accessible forms

Make forms usable for everyone with proper labels, fieldset and legend, helpful hints and error messages, and sensible autocomplete values.

13 minFormsUpdated 18 October 2026

By the end of this lessonBuild a form that works with a keyboard and a screen reader, using labels, grouped fields, descriptions, error messages and autocomplete.

Forms are where accessibility is won or lost

A badly made form can lock people out: someone using a screen reader hears "edit text" with no idea what to type; someone using only a keyboard cannot reach the button; someone with a tremor cannot hit a tiny checkbox. The fixes are mostly basic HTML you already know. The rule of thumb is that every control needs a name, a purpose and a way to be reached by keyboard.

Labels, properly connected

There are two correct ways to connect a label and a field.

html
<!-- 1. for and id -->
<label for="city">City</label>
<input type="text" id="city" name="city">

<!-- 2. wrapping -->
<label>City <input type="text" name="city"></label>

Either way, you get three benefits: a screen reader announces "City, edit text"; clicking the label focuses the field; and the clickable area is bigger, which matters a lot for checkboxes and radio buttons on phones.

Labels must be visible text, placed close to the control. Hiding labels because they "spoil the design" removes the only thing that says what the field is.

Placeholder is not a label

html
<!-- Weak -->
<input type="text" placeholder="Full name">

<!-- Better -->
<label for="n">Full name</label>
<input type="text" id="n" name="name" placeholder="e.g. Asha Verma">

A placeholder vanishes the moment someone types, so they cannot check what the field was. Its default colour is also often too light to read. Use it for an example, never as the field's name.

When several controls answer one question, wrap them in fieldset and give it a legend:

html
<form>
  <fieldset>
    <legend>How should we contact you?</legend>
    <label><input type="radio" name="contact" value="email" checked> Email</label><br>
    <label><input type="radio" name="contact" value="phone"> Phone</label>
  </fieldset>
</form>

A screen reader says "How should we contact you? Email, radio button, one of two". Without the legend, the user would hear "Email" and "Phone" with no question.

Hints and error messages

Give extra help in text, and connect it to the field with aria-describedby, whose value is the id of the text:

html
<form>
  <p>
    <label for="pw">Password</label><br>
    <input type="password" id="pw" name="pw" aria-describedby="pw-hint pw-error" minlength="8">
  </p>
  <p id="pw-hint" style="font-size:.9em;color:#555">At least 8 characters.</p>
  <p id="pw-error" style="color:#b91c1c">Password is too short.</p>
</form>

When the field gets focus, a screen reader reads the label and then the description. For fields in error, also set aria-invalid="true", and say what to do, not just that something is wrong: "Enter a date like 12/03/2026" beats "Invalid".

Do not rely on colour alone to show errors or required fields. Add words or an icon with a text label.

Required fields

Mark required fields in two ways: the required attribute (the browser prevents submitting empty) and a visible cue, for example "(required)" after the label. Choose one convention and use it everywhere.

autocomplete

Browsers can fill in addresses, names and emails, but only if they know what each field is. The autocomplete attribute tells them:

html
<input type="text" name="fullname" autocomplete="name">
<input type="email" name="email" autocomplete="email">
<input type="tel" name="phone" autocomplete="tel">
<input type="text" name="postal" autocomplete="postal-code">
<input type="password" name="pw" autocomplete="new-password">

This helps people with motor or memory difficulties and saves everyone time on a phone. Use autocomplete="off" only when there is a real reason.

Keyboard and focus

  • All controls should be reachable with Tab, in a logical order. Source order decides tab order, so write your HTML in the order people should visit the fields.
  • Keep the visible focus outline that browsers draw. If your CSS removes it, replace it with something equally clear.
  • A button or input type="submit" can be pressed with Enter or Space; a div made to look like a button cannot, without extra work.

Common mistakes

  • Placeholder as the only label.
  • Label text that is not connected (no for/id match, or not wrapped).
  • Radio buttons and checkboxes with no group question.
  • Errors shown only in red, or listed far from the field.
  • Disabling paste in password and email fields; it hurts people using password managers.
  • A clickable div instead of a button.

Exercise

Improve this form snippet: add a visible label, a hint "We never share your email", connect the hint, and set autocomplete.

html
<input type="email" placeholder="Email" name="email">
Show one possible answer
html
<label for="email">Email address</label>
<input type="email" id="email" name="email" autocomplete="email" aria-describedby="email-hint" required>
<p id="email-hint">We never share your email.</p>

Key points

  • Every form control needs a visible label connected to it, either by wrapping it or with for and id.
  • Placeholder text is a hint, not a label; it disappears when typing and has poor contrast in many browsers.
  • fieldset and legend group related controls such as a set of radio buttons under their question.
  • aria-describedby links a field to hint or error text so it is read out with the field.
  • autocomplete values let browsers fill in names, addresses and emails, which helps everyone and is required for some users.

Check yourself

1. A text box has a placeholder 'Email' but no label. What is wrong?
2. When should you use fieldset and legend?
3. What does aria-describedby do?
4. What is the benefit of autocomplete="email"?

Free tools for this lesson