/ โ† Accessibility Fixes / Form Labels
In this guide
  1. What a form label actually is
  2. Label patterns that work
  3. Why a placeholder is not a label
  4. Groups, hints and error messages
  5. Fixing labels in common platforms
  6. The fix, step by step
  7. Edge cases the checker may raise
  8. Stopping unlabelled fields coming back
  9. Questions and answers

What a form label actually is

Every form control has an accessible name: the words assistive technology announces when the control receives focus. A screen reader reads it out, voice control software lets people say it to move to the field, and browsers use it alongside other hints when they autofill. A label is simply the most reliable way of giving a field that name, while also showing it on screen.

The browser works out the name from several possible sources, in a fixed order of priority:

  1. aria-labelledby, pointing at the id of other text on the page;
  2. aria-label, a text string on the field itself;
  3. a <label> element connected to the field;
  4. the title attribute;
  5. for some fields, the placeholder, as a last resort.

That order explains several confusing results. A field can have a perfect visible label and still announce something else, because an aria-label added by a developer or plugin overrides it. And a field with only a placeholder may technically have a name in some browsers, yet still fail, because the visible text disappears as soon as someone types.

The WCAG criteria behind form label findings

CriterionLevelWhat it means for forms
1.3.1 Info and RelationshipsAThe link between a label and its field, and between a group name and its options, must exist in the code, not only visually.
3.3.2 Labels or InstructionsAFields that need input have labels or instructions people can see.
4.1.2 Name, Role, ValueAEvery control, including custom dropdowns and toggles, has a name assistive technology can read.
2.5.3 Label in NameAThe visible label text is included in the accessible name, so voice users can say what they see.
1.3.5 Identify Input PurposeAAFields collecting the user's own details declare their purpose, normally with autocomplete.
3.3.1 Error IdentificationAErrors are described in text and the field in error is identified.

Label patterns that work

Explicit label with for and id

<label for="enquiry-email">Email address</label>
<input id="enquiry-email" name="email" type="email" autocomplete="email">

The for value must exactly match the input's id, including capital letters. This is the most widely supported pattern. It also makes the label clickable, so tapping the words "Email address" puts the cursor in the box, which helps anyone with small targets or a shaky hand, and makes tiny checkboxes and radio buttons much easier to hit.

Wrapped label

<label>
  <input type="checkbox" name="newsletter" value="yes">
  Send me the monthly newsletter
</label>

Putting the field inside the label connects them without ids. It is valid HTML and works in current browsers and screen readers. Many teams still add for and id as well, because some older assistive technology handled the wrapped form less consistently and it removes any doubt.

A label you cannot see

Sometimes there is genuinely no room for visible text, such as a search box beside a magnifying-glass button in the header. Keep a real label element and hide it visually with a class that leaves it available to assistive technology:

<label for="site-search" class="visually-hidden">Search the shop</label>
<input id="site-search" type="search" name="q">
<button type="submit">Search</button>

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

Do not hide labels with display: none or visibility: hidden. Those remove the text from most assistive technology as well as from the screen, and the field loses its click target. Hidden labels should be the exception; almost every field is easier for everyone with visible words beside it.

When aria-label or aria-labelledby is right

Use aria-labelledby when existing visible text already names the field, such as a table column heading above a quantity box. Use aria-label only when there is no suitable text at all and a hidden label is not possible. In both cases, keep the words close to what sighted users see, so voice control and screen reader users are talking about the same thing.

Why a placeholder is not a label

Placeholder-only forms are the most common cause of form label findings, especially in newsletter sign-ups, header search boxes and minimal contact forms. They look tidy, but they cause real problems:

Keep placeholders only for a short example of the expected format, such as placeholder="e.g. S40 1AB", with the real label shown above the field. If a design uses a "floating label" that starts inside the box and moves above it on focus, check that it is a real label element and that it never disappears.

Groups, hints and error messages

Radio buttons and checkbox groups

Each option needs its own label, but the question they answer needs a name too. Without it, a screen reader user hears "Yes, radio button, 1 of 2" with no idea what they are agreeing to.

<fieldset>
  <legend>How should we contact you?</legend>
  <input type="radio" id="contact-phone" name="contact" value="phone">
  <label for="contact-phone">Phone</label>
  <input type="radio" id="contact-email" name="contact" value="email">
  <label for="contact-email">Email</label>
</fieldset>

Screen readers announce the legend when focus first enters the group. Keep legends short, because some screen readers repeat them for each option. Use a fieldset for date-of-birth fields split into day, month and year boxes as well; each box still needs its own label such as "Day".

Hints and required fields

<label for="booking-ref">Booking reference (required)</label>
<p id="booking-ref-hint">Six letters and numbers, printed at the top of your confirmation email.</p>
<input id="booking-ref" name="ref" required aria-describedby="booking-ref-hint">

The label gives the name; aria-describedby connects extra help that is read after it. The required attribute tells assistive technology the field is mandatory. If you use an asterisk, explain it once at the top of the form, and consider writing "required" or marking optional fields instead.

Error messages

<label for="enquiry-phone">Phone number</label>
<input id="enquiry-phone" name="phone" type="tel" autocomplete="tel"
       aria-invalid="true" aria-describedby="enquiry-phone-error">
<p id="enquiry-phone-error" class="field-error">Enter a UK phone number, like 01246 000000</p>

Put the message next to the field, in text, and connect it with aria-describedby. Set aria-invalid="true" only while the error applies. A red border alone fails, because colour cannot be the only way information is shown. For long forms, a summary at the top listing each error as a link to its field helps everyone.

Fixing labels in common platforms

Platform or toolUsual causeWhere to fix it
Contact Form 7 (WordPress)Form tags written without surrounding label text, or labels removed to save spaceIn the form template, wrap each tag in a label, for example <label>Your name [text* your-name autocomplete:name]</label>
Gravity Forms, WPForms, Ninja FormsLabel visibility set to hidden and a placeholder used insteadField settings: show the field label, keep placeholders for examples only
Elementor and other builder form widgetsThe option to show labels switched off in the widgetForm widget content settings: turn labels on, then restyle them
Shopify themesNewsletter and search inputs in the footer or header with placeholder text onlyThe theme section's Liquid file: add a label, visually hidden if space is tight
Embedded forms (email marketing, CRM, booking tools)The third party's default template, sometimes inside an iframeThe provider's form editor or custom HTML option; if it cannot be fixed, ask the provider or choose another
React, Vue and other frameworksCustom input components that render an input without passing an id to the label, or duplicate ids when a component is reusedGenerate a unique id per instance, for example with React's useId, and pass it to htmlFor and the input
โš ๏ธ Duplicate ids are a quiet cause of broken labels. If the same form appears twice on a page, such as a newsletter box in both the sidebar and the footer, both copies may use id="email". The second label then points at the first field, and the second field has no name at all.

The fix, step by step

Step 1

List every field and its current name

Run the Accessibility Audit on each page with a form, including the header search, footer newsletter, contact, booking, login and checkout pages. For each finding, inspect the field and open the accessibility pane in the browser developer tools, which shows the computed name and where it came from. Note fields with no name, a name from a placeholder or title, or a name that does not match the words on screen.

Step 2

Connect a visible label to each input

Give every text box, select, textarea, checkbox and radio button a label element with clear words such as Email address or Postcode. Connect it with a for attribute that exactly matches a unique id on the field, or wrap the field inside the label. Remove any aria-label that says something different from the visible text, because it overrides the label and confuses voice control users.

Step 3

Replace placeholder-only fields

Find every field where the only text is a placeholder, typically in newsletter boxes, header search and compact contact forms. Move that text into a real label shown above or beside the field, and keep the placeholder only for a short format example if it helps. Where the design truly has no room, use a visually hidden label rather than none, and check that any placeholder left behind meets contrast requirements.

Step 4

Group radio buttons and checkboxes

Wrap each set of related options in a fieldset with a legend that states the question, such as How should we contact you?, and give each option its own label. Do the same for split date fields and address blocks where several boxes belong together. For custom controls that cannot use a fieldset, use role="group" with aria-labelledby pointing at the visible question.

Step 5

Attach hints, required markers and errors

Connect format hints and error messages to their fields with aria-describedby, so they are read after the label. Add the required attribute to mandatory fields and explain any asterisk in words. Submit the form empty and with wrong values, and check each error appears as text beside the right field, that aria-invalid is set only while the error applies, and that colour is not the only signal.

Step 6

Add autocomplete to personal details

For fields that collect the visitor's own information, add the matching autocomplete value: name, given-name, family-name, email, tel, organization, street-address or postal-code. This lets browsers fill the form accurately and supports people who find typing slow or difficult. Do not add the visitor's own autocomplete values to fields that ask about someone else, such as a gift recipient's name, because the browser would then fill in the wrong person's details.

Step 7

Test with a screen reader and voice names

Tab through the form with NVDA on Windows or VoiceOver on a Mac and listen: every field should announce its label, its type, whether it is required and any hint. Check each group announces its question. Then read each visible label aloud and confirm it appears in the computed name, which is what voice control users rely on. Finally, run the Accessibility Audit again to confirm the findings have cleared.

Edge cases the checker may raise

Stopping unlabelled fields coming back

Questions and answers

1. Is a placeholder enough to label a form field?

No. Placeholder text disappears as soon as someone starts typing, is usually too pale to meet contrast requirements, vanishes when a browser autofills the form, and is not treated as a name consistently by every browser and screen reader. A field needs a label that stays visible. You can keep a placeholder for a short example of the format, such as a sample postcode, but the label itself should be a proper label element connected to the field.

2. What is the difference between aria-label and a label element?

A label element is visible text connected to a field, which also makes the text clickable. The aria-label attribute is an invisible text string placed directly on the field that only assistive technology reads. Because aria-label wins over a label element when the browser works out the name, adding one that says something different creates a mismatch. Prefer a visible label element in almost every case, and keep aria-label for rare fields where no visible text can exist.

3. Do radio buttons need a fieldset and legend?

When the options answer a question, yes. Each radio button has its own label, such as Phone or Email, but those words mean nothing without the question they answer. Wrapping the set in a fieldset with a legend gives the group a name that screen readers announce when focus enters it. For a single checkbox such as agreeing to terms, the checkbox label alone is enough. For custom controls, role group with aria-labelledby does the same job.

4. Can I hide form labels to keep the design clean?

You can hide a label visually in a small number of cases, such as a search box next to a clearly marked search button, using a visually hidden class that keeps the text available to assistive technology. Do not use display none, which removes the label for screen readers too. For most forms, visible labels are better for everyone, including older visitors, people using autofill and people who are interrupted halfway through filling in the form.

5. How do I check what a screen reader will announce for a field?

Open the browser developer tools, select the field in the elements panel and open the accessibility pane. In Chrome, Edge and Firefox this shows the computed name, the role and where the name came from, such as a label element, aria-label or placeholder. That tells you what assistive technology receives without installing anything. Then confirm with a real screen reader such as NVDA on Windows or VoiceOver on a Mac, because announcements vary slightly between them.

6. What is Label in Name and why does it matter?

Label in Name is WCAG success criterion 2.5.3. It says that when a control has visible text, its accessible name must contain that same text. It matters most for people using voice control, who operate the page by saying what they see, such as click Send. If the button shows Send but its hidden name is Submit enquiry form, the voice command may fail. Starting the accessible name with the exact visible words is the safest approach.

7. Why does my form label still fail even though it looks connected?

The most common reasons are a for value that does not exactly match the field id, including capital letters, two elements on the page with the same id, an aria-label or aria-labelledby on the field that overrides the label, or a label element that is present but empty or hidden with display none. Inspect the field in the accessibility pane of the developer tools, which shows the name actually computed, and work back from there.

Check your forms now

The Accessibility Audit tests your page against WCAG 2.2 level AA, lists each finding with the element that failed and the success criterion behind it, and links to the guide that fixes it.

Open Accessibility Fixes โ†’
๐Ÿ’ฌ Got a problem?
Related Guides: All Accessibility Fixes  ·  Fixing ARIA Labels  ·  Fixing Form Validation  ·  Forms AI Agents Can Fill  ·  Learning Hub

About aiwebpageseo

aiwebpageseo.com is a data-driven SEO and AEO (Answer Engine Optimisation) platform providing a free suite of technical SEO tools. Rather than relying on AI-theorised assumptions, the platform analyses live URL performance, delivering objective diagnostics, page speed metrics, CLS debugging, and site crawl data alongside actionable technical tutorials.