Forms Rule

Form fields must have labels label

Every input and textarea needs a label that is programmatically tied to it, not just sitting nearby. A label element with a for attribute matching the field's id is the normal way. Without it, a screen reader announces the field as edit text and the person has to guess what to type. A placeholder does not count: it vanishes as soon as typing starts and many screen readers skip it.

Websight reports this as Form elements must have labels

Who it affects

Someone using a screen reader to report a missed bin collection on a council website lands on a field and hears edit text. Is it the postcode, the house number or the date? They cannot tell without leaving the field to hunt for clues.

Someone with a memory impairment who has started typing loses the placeholder the moment the first character goes in and can no longer see what the field was for.

Someone using voice control says click postcode but the field has no name to match, so focus does not move.

Broken versus fixed

Both examples are live and rendered in a sandboxed frame. The broken one is deliberately broken.

Broken

Tab into the first field with a screen reader on: edit text, or at best Postcode, edit text, until you type one character and the hint disappears.

Fixed

Announced: Postcode, edit text. The label stays visible while typing, and clicking it focuses the field.

Show the markup behind both examples
Broken
<style>body{font-family:system-ui;padding:16px;margin:0}input{display:block;padding:8px;font-size:15px;border:1px solid #888;border-radius:6px;width:220px;margin-bottom:10px}</style>
<h2 style="font-size:17px;margin:0 0 10px">Report a missed bin collection</h2>
<input type="text" placeholder="Postcode">
<input type="text" placeholder="House number or name">
Fixed
<style>body{font-family:system-ui;padding:16px;margin:0}label{display:block;font-size:14px;margin-bottom:4px}input{display:block;padding:8px;font-size:15px;border:1px solid #888;border-radius:6px;width:220px;margin-bottom:10px}</style>
<h2 style="font-size:17px;margin:0 0 10px">Report a missed bin collection</h2>
<label for="pc">Postcode</label>
<input id="pc" type="text" autocomplete="postal-code">
<label for="hn">House number or name</label>
<input id="hn" type="text">

Test it by hand in two minutes

  1. Click the visible label text next to a field. If the cursor jumps into the field, the label is connected. If nothing happens, it is not.
  2. Right click the field and choose Inspect. Look for an id on the input and a label element with a matching for attribute, or a label wrapped around the input.
  3. Turn on VoiceOver (Cmd+F5 on a Mac) or NVDA and Tab through the form. Each field should be announced with its purpose, for example Postcode, edit text.
  4. Type a character into each field. The thing that told you what the field was for should still be visible.

The fix

Before
<input type="text" placeholder="Postcode">
After
<label for="pc">Postcode</label>
<input id="pc" type="text">

The for value must exactly match the id, and the id must be unique on the page. Keep the placeholder only for an example value, such as SW1A 1AA, never as the only label.

Wrap the field in the label

Before
<input type="checkbox" name="garden"> Garden waste bin
After
<label>
  <input type="checkbox" name="garden"> Garden waste bin
</label>

Wrapping works without ids and makes the whole text clickable, which is handy for checkboxes and radios.

Field where a visible label does not fit

Before
<input type="search" placeholder="Search">
After
<input type="search" aria-label="Search the site" placeholder="Search">

aria-label gives a spoken name with no visible text. Use it sparingly; a visible label helps everyone, including sighted people who forget what a field was for.

Label that already exists elsewhere

Before
<th id="qty">Quantity</th>
...
<input type="number">
After
<th id="qty">Quantity</th>
...
<input type="number" aria-labelledby="qty">

In a table of fields, point each input at the column header with aria-labelledby rather than repeating the text.

Common mistakes

  • Using a placeholder as the only label.
  • Putting the label text in a p or div next to the field with no for and id to connect them.
  • Giving several fields the same id, so the for attribute only reaches the first one.
  • Using title as the label; it is not shown on touch screens and not reliably announced.
  • Writing a label element but leaving the for attribute empty or pointing at the wrong id.

WCAG criteria this rule maps to

axe-core tags this rule as WCAG 2.2 level A. It is one of the checks for:

The scanner can see a field with no connected label, aria-label, aria-labelledby or title. It cannot tell whether a label that exists is clear, or whether the words match what the field actually wants. Automated tools find only part of the accessibility problems on a page; a pass on this rule is not a pass on the criterion.

Scan your own page for this and 63 other checks

Open any page in Chrome, click Websight, and get a score out of 100 with every issue explained and a draft fix snippet per element.

Add Websight to Chrome

Free scans, no account, nothing leaves your computer. Automated tools find only part of the problems; the extension says so on every report.