Search topics
Required fields marked only by colour
A booking form colours the labels of its required fields red, with no word, symbol or required attribute, so only people who see the colour and guess its meaning know which fields they must fill in.
The problem
People who can't see the red, or don't know what it means, find out which fields are required only when the form is sent back.
A cookery school's booking form asks for a full name, an email address, a phone number and any dietary needs. The labels "Full name" and "Email" are red; "Phone" and "Dietary needs" are dark grey. The designer meant red to say "required", and to them it obviously does. Someone who can't tell red from grey sees four ordinary labels. A screen reader user hears "Full name, edit text" and "Phone, edit text", with nothing to set them apart. A visitor who fills in only their phone number and presses "Book my place" gets the form back with two errors, and learns the rules only then.
3.3.2 asks for labels or instructions when content needs input. Which fields must be filled in is one of those instructions: the W3C Understanding page names required fields as an example. Here that instruction is given by colour alone, and nothing in the page explains the colour, so most people don't receive it. The fields also have no required attribute, so the browser can't tell assistive technology that they are required. Colour as the only sign also fails 1.4.1, but the fix for both is the same: put the instruction in words.
The barrier is invisible to the people who made the form, because they know what the red means. Everyone else pays for it with a failed submission, and on a phone that often means scrolling back up through the form to find the fields with errors.
4 of 10 groups affected
- No vision (affected)
- Low vision (affected)
- Colour vision (affected)
- No hearing (not affected)
- Hard of hearing (not affected)
- No speech (not affected)
- Motor (not affected)
- Reach, strength (not affected)
- Cognitive (affected)
- Seizures (not affected)
- Without perception of colour People who can't tell red from black see four identical labels and no sign that two fields must be filled in.
- Without vision Without the required attribute, a screen reader announces each field the same way, so the colour says nothing at all.
- Limited language, cognitive and learning abilities Even when the red is visible, its meaning is a guess, and people learn they were wrong only when the form comes back with errors.
- Limited vision At high zoom or with a magnifier, only one label is in view at a time, so there is no other label to compare its colour with.
Scanners check that each field has a label, and these do, so the form passes. No rule can tell that a red label was meant to mean "required", or that the server rejects an empty email. A quick AI fix often adds aria-required="true" to the red fields: screen reader users then hear "required", but the visible form is unchanged, and everyone who can't read the colour is still guessing. Another common patch adds an asterisk with no explanation, which leaves people wondering what the star means. Whether the visible marks match what the server needs is something a person has to compare.
Try it
Which fields must you fill in? Decide, then press Tab through the form.
Turn on greyscale to see the form without colour. Below it, check whether a screen reader hears "required".
Broken Can you fix this?
(Tab to a field)
A recreated demo. The broken version is intentionally inaccessible.
The fix
Say it in words in the labels, and add the required attribute to the same fields.
- 1Show which fields are required in visible text, in the label or explained before the first field.
- 2Give every required field the required attribute, and only those.
- 3Don't let colour, bold or a placeholder be the only sign.
<style> .is-required { color: #b3261e; }</style> <label for="name" class="is-required">Full name</label><input id="name" name="name" type="text" autocomplete="name"> <label for="email" class="is-required">Email</label><input id="email" name="email" type="email" autocomplete="email"> <label for="phone">Phone</label><input id="phone" name="phone" type="tel" autocomplete="tel"> <label for="diet">Dietary needs</label><input id="diet" name="diet" type="text">The only difference between a required and an optional field is the colour of its label. Nothing on the page explains it, and the code doesn't mark any field as required.
The word is part of each label, so everyone reads it in the same place as the field's name, and needs no key. The required attribute tells assistive technology the same thing: a screen reader says "Full name (required), edit text, required". You can keep the red as extra styling on the word, as long as the word is there.
All three pass 3.3.2 and all three keep the required attribute. Writing "(required)" in each required label needs no explanation and nothing else on the page, so choose it when fewer than about half the fields are required. When nearly every field is required, mark the optional ones instead: the form reads more calmly and the word still sits on each field it applies to. The asterisk is the shortest and the most familiar, and suits sites that already use it on every form: keep it consistent across the site, and make the star large and dark enough to see.
Put the explaining line where people will see it. The optional-field and asterisk fixes both rely on a line before the first field. Keep it directly above the form, not in a page intro or a footer, so people who are zoomed in or arrive at the form from a link still pass it.
Keep the word in the label. Put "(required)" or "(optional)" inside the label element, not in a placeholder, a tooltip or a separate div. Inside the label, it is visible next to the field and part of the name voice control and screen readers use.
Only mark what the server needs. Add required where an empty field is rejected, and nowhere else. A field that says "(required)" but is accepted empty, or the opposite, teaches people to ignore the marks. Generate the mark and the attribute from the same field setting in your form component, so they can't drift apart.
Browser validation. The required attribute also turns on the browser's own check and its message bubble. If you show your own error messages, add novalidate to the form: the fields keep required, so screen readers still announce it, and your errors take over. For the messages themselves, see the guide on form errors.
Custom controls. A custom dropdown or date picker built from divs can't take required. Give it aria-required="true" alongside the visible word, or, better, replace it with a native control.
Groups of radio buttons and checkboxes. Put the word in the legend, not on each option: "Course date (required)". Add required to each radio button in the group.
Japanese forms. Many Japanese forms use a 必須 badge. That passes, because it is text: keep it inside the label, give it enough contrast, and don't rely on its colour alone.
Verify the fix
4 checks, no mouse.
Test with: Keyboard, Screen reader, Zoom
Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat when fields are added to the form or the shared field component changes.
Limits
This is a starting pattern, not a guarantee for every application. It covers how people learn which fields are required before they type, not the error messages they see afterwards. Formats, such as a date order or a postcode pattern, are instructions too, and need their own text. Forms built by third-party widgets or content editors need the same check. Test the complete journey with your target assistive technology.
This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.
Keep this fixed as your code changes.
Turn guides like this into rules your coding agents and CI follow, then have the result retested with a keyboard and screen readers.