Fixing Form Labels
A form field with no proper label is one of the quickest ways to lose an enquiry or a sale. A sighted visitor may guess what a box is for from a faded placeholder, but a screen reader user hears only "edit text", a voice control user has no name to say, and a browser cannot autofill it reliably.
This guide explains what counts as a label, why placeholders and nearby text do not, and how to label single fields, groups, hints and error messages so every visitor can complete your contact, booking and checkout forms.
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:
aria-labelledby, pointing at the id of other text on the page;aria-label, a text string on the field itself;- a
<label>element connected to the field; - the
titleattribute; - 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
| Criterion | Level | What it means for forms |
|---|---|---|
| 1.3.1 Info and Relationships | A | The 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 Instructions | A | Fields that need input have labels or instructions people can see. |
| 4.1.2 Name, Role, Value | A | Every control, including custom dropdowns and toggles, has a name assistive technology can read. |
| 2.5.3 Label in Name | A | The visible label text is included in the accessible name, so voice users can say what they see. |
| 1.3.5 Identify Input Purpose | AA | Fields collecting the user's own details declare
their purpose, normally with autocomplete. |
| 3.3.1 Error Identification | A | Errors 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:
- The text vanishes when someone starts typing, so anyone who is interrupted, or who has memory or attention difficulties, loses track of what the field was for.
- Placeholder text is usually pale grey and often fails the 4.5:1 contrast ratio needed for normal text.
- When a browser or password manager autofills the form, every placeholder is replaced at once and the person cannot check that each value went into the right box.
- Support for the placeholder as an accessible name varies, so some combinations of browser and assistive technology announce nothing useful.
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 tool | Usual cause | Where to fix it |
|---|---|---|
| Contact Form 7 (WordPress) | Form tags written without surrounding label text, or labels removed to save space | In the form template, wrap each tag in a label, for example <label>Your name [text* your-name autocomplete:name]</label> |
| Gravity Forms, WPForms, Ninja Forms | Label visibility set to hidden and a placeholder used instead | Field settings: show the field label, keep placeholders for examples only |
| Elementor and other builder form widgets | The option to show labels switched off in the widget | Form widget content settings: turn labels on, then restyle them |
| Shopify themes | Newsletter and search inputs in the footer or header with placeholder text only | The 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 iframe | The provider's form editor or custom HTML option; if it cannot be fixed, ask the provider or choose another |
| React, Vue and other frameworks | Custom input components that render an input without passing an id to the label, or duplicate ids when a component is reused | Generate a unique id
per instance, for example with React's useId, and pass it to htmlFor and the
input |
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
- Buttons are not labels. A submit button gets its name from its text, or from
valueon aninput type="submit". An icon-only button, such as a magnifying glass, needs visually hidden text or anaria-label. That is a button naming problem rather than a label one, and our ARIA labels guide covers it. - Custom dropdowns. Select menus rebuilt from
divelements for styling often have no name, no role and no keyboard support. A nativeselectwith a label is simpler and more robust; if a custom control is essential, it needs a label connected witharia-labelledbyas well as the correct roles. - Hidden fields. Inputs with
type="hidden"do not need labels. Spam traps, or honeypots, should be hidden from everyone withdisplay: noneor similar, so they never reach a screen reader or the keyboard. - Several fields, one label. A single label cannot name two inputs. A phone number split into area code and number needs a label for each part, even if one is visually hidden, plus a fieldset or group name for the whole.
- Labels with links inside. A checkbox label such as "I agree to the terms" may contain a link. Clicking the link text should open the terms, not tick the box, so keep the link short and test both behaviours.
- Title attributes. A
titlecan supply a name, but the tooltip it shows is not available to keyboard or touch users. Replace it with a label.
Stopping unlabelled fields coming back
- Build one input component. On custom sites, create a single field component that always renders a label, a unique id and optional hint and error slots, and use it everywhere.
- Set defaults in your form builder. Turn labels on in the global settings of the form plugin, so new forms start with them.
- Check third-party embeds before launch. Newsletter, booking and quote tools are added by marketing teams and often skip review. Test each one with the checker and a keyboard before it goes live.
- Include forms in release testing. Any change to a form, including a redesign that shortens it, should be tested with a screen reader for a few minutes.
- Keep the labels short and plain. Clear words such as "Postcode" help everyone, including people using translation tools and AI agents that read the page.
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.
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 โ