PLAINFINCH learn by building

Labels for every field

You will give every field on a form a visible label that is joined to it, so screen readers say the right question.

What does a label do for a form field?

A label gives a field its accessible name. When focus lands on the field, a screen reader says the name and the role together: “Where did you see it?, edit text”. Without a label, it says “edit text” and nothing else, and the person has to guess from the text around it, if they can find it. Voice control users need the name too: they say “click Where did you see it” and the software looks for a field with that name.

A connected label also helps everyone with a mouse or a touch screen. Clicking or tapping the label puts the cursor in the field, or ticks the checkbox, which gives a much bigger target. People with tremors and people on small phones notice the difference straight away.

Three WCAG 2.2 criteria cover this. 1.3.1 Info and Relationships asks that the link between a label and its field is written in the code as well as shown in the layout. 3.3.2 Labels or Instructions asks that fields have labels people can see. 4.1.2 Name, Role, Value adds that every control has a name assistive technology can read.

How do you connect a label to its field?

Give the field an id and give the <label> a for attribute with the same value. The browser links them in the accessibility tree, wherever they sit in the HTML. The match is exact and case-sensitive: for="count" does nothing for a field with id="birds", which is the bug on the third field of the demo.

The other way is to wrap the field inside the label. That links them without any id. It is handy for checkboxes, where the text sits right beside the box, and it avoids the problem of two fields with the same id. Both ways are equally valid. Pick one style for a project and stick to it, since mixed styles make bugs harder to see.

A label without for and without a field inside it is just text. That is what happened to “Where did you see it?” in the demo. It looks like a label to a sighted person and means nothing to the browser.

<label for="place">Where did you see it?</label>
<input id="place">

<label><input type="checkbox" name="photo"> I have a photo</label>
FigureTwo label and field pairs from the bird sighting form. label for place matches input id place, so the field is read as Where did you see it?, edit text. label for count does not match input id birds, so the field has no name.Two label and field pairs from the bird sighting form. label for place matches input id place, so the field is read as Where did you see it?, edit text. label for count does not match input id birds, so the field has no name.
The for value must equal the id exactly. "place" to "place" gives the field its name; "count" to "birds" links nothing, so the number field is read with no name at all.

Why isn’t a placeholder enough?

The placeholder is the grey hint inside an empty field. It vanishes as soon as someone types, so people with short-term memory difficulties, people who get interrupted and anyone checking their answers later lose the question. Placeholder text is often pale and fails contrast too, and some people mistake it for a value already filled in and skip the field.

Browsers do use a placeholder as the accessible name when nothing better exists, so a screen reader may still say it. Treat that as a fallback that rescues broken pages. Plan for a real label every time. The Checks view flags fields named only by a placeholder for that reason.

Placeholders still have a job: a short example of the format, like e.g. 3 or [email protected], below or beside a real label. Keep anything people need, such as rules about format, in visible text that stays.

What about fields that have no room for a visible label?

A search box in a header is the usual case. Designers want a single field and a Search button. The best answer is still a visible label, even a small one. When that truly won’t fit, give the field a name with aria-label="Search parts" or point aria-labelledby at the button’s id. The field then has a name, and the button beside it tells sighted people what it does.

Use aria-labelledby when the words that name a field already exist on the page in another element. It can point at more than one id, and the name is built from them in order. A row in a price table, for example, might label a quantity field with the product name and the column heading together. Remember that ARIA names are invisible: they help screen reader users and do nothing for someone who forgets what a field was for.

<form role="search">
  <input id="q" type="search" aria-label="Search parts">
  <button type="submit">Search</button>
</form>

How should the label text match what people see?

Voice control users speak the words they see. If a button shows “Send” but its aria-label says “Submit form”, saying “click Send” fails. 2.5.3 Label in Name asks that the accessible name contains the visible text, best at the start. The same applies to fields: a visible label of “Postcode” should not be overridden by an aria-label of “Zip”.

Keep label text short and specific. Write the question people are answering, “How many?”, “Where did you see it?”, and put extra help in a separate hint linked with aria-describedby. Mark optional fields in words, as the notes field does, and never rely only on colour or position to say what a field is for.

How do you test labels?

Open the **Screen reader** view and read every field line. Each should start with words that make sense on their own, then the role: “Which bird did you see?, edit text”, “How many?, spin button”. A line that starts with “unlabeled” or with a placeholder means a missing or broken label.

Then click each label in the **Page** view. If the cursor jumps into the field, they are connected. This is the fastest test there is and needs no tools. Tab through the form in the **Keyboard** view as well, which lists every field with its name, and look in **Checks** for id values used twice, since two fields sharing one id both get the same label.

What do AI tools get wrong with labels?

Generated forms often use placeholders in place of labels because the result looks clean in a screenshot. They also copy and paste blocks of fields and forget to change the id and for pairs, so two labels point at the same field. Some add aria-label to every input on top of a visible label, with different words, which breaks Label in Name for voice users.

When you review generated form code, check three things: every field has a <label> or is wrapped in one, every for matches exactly one id, and no aria-label contradicts the visible text. Then click each label once.

Field notes

  • A label gives a field the name a screen reader says when focus lands on it.
  • Match the label's for to the field's id to join them.
  • A placeholder disappears once someone types, so it cannot replace a label.
  • Label text should match the words people see on screen.

Easy to get wrong

The placeholder disappears as soon as people type, is often too pale to read, and is only a fallback name. A label stays visible and is always read.

A <label> without for and without a field inside it is plain text. Nothing connects it to the field, so a screen reader says only “edit text”.

An id must be unique. When two fields share one, labels attach to the wrong field or to both, and the names screen readers read come out mixed up.

aria-label replaces the visible label in the accessibility tree. Voice users who say “Postcode” won’t find the field.

Questions people ask

Is wrapping the field in a label as good as using for?

Yes. Browsers and screen readers treat both the same way. Wrapping avoids id mistakes and is common for checkboxes. Using for lets you place the label and field anywhere in the HTML, which suits grid layouts.

Can a label be visually hidden?

It can, with a visually hidden class, and screen readers will read it. Sighted people then lose the label, so use it only when the purpose is clear from the design, as with a search box beside a Search button.

Does the title attribute count as a label?

Browsers use title as a name when there is no label, but it appears only on mouse hover and never on touch screens or for keyboard users. Use a real label instead.

What about a button that is also a field, like a file input?

An <input type="file"> needs a label like any other field. The browser’s button text, such as “Choose file”, does not tell people what the file is for.

Keep going