# Required fields marked only by colour

Source: https://easeweb.dev/learn/required-fields
Topics: Forms > Required fields are marked in text (WCAG 3.3.2)
The fix: Say in visible text which fields are required, and add the required attribute to the same fields. Write "(required)" in each required field's label, or mark the optional fields "(optional)" with a sentence before the form saying the rest are required. Or mark the required fields with an asterisk and explain it in a line before the first field.
Test with: keyboard, screen reader, zoom
References: https://www.w3.org/WAI/WCAG22/Understanding/labels-or-instructions.html https://www.w3.org/WAI/WCAG22/Techniques/html/H90 https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA2 https://www.w3.org/WAI/tutorials/forms/instructions/ https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/required

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.

## What happens

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.

## Why it fails

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.

## Who is affected

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.

## What automation and AI miss

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.

## Before: required shown only by a colour

```html
<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.

## After: "required" in each required label

```html
<label for="name">Full name <span class="req">(required)</span></label>
<input id="name" name="name" type="text" autocomplete="name" required>

<label for="email">Email <span class="req">(required)</span></label>
<input id="email" name="email" type="email" autocomplete="email" required>

<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 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.

## After: mark the optional fields instead

```html
<p>All fields are required unless marked optional.</p>

<label for="name">Full name</label>
<input id="name" name="name" type="text" autocomplete="name" required>

<label for="email">Email</label>
<input id="email" name="email" type="email" autocomplete="email" required>

<label for="phone">Phone <span class="opt">(optional)</span></label>
<input id="phone" name="phone" type="tel" autocomplete="tel">

<label for="diet">Dietary needs <span class="opt">(optional)</span></label>
<input id="diet" name="diet" type="text">
```

When most fields are required, marking the few optional ones keeps the labels shorter and puts the word where the decision is: on the fields people may skip. The sentence before the first field tells people what an unmarked field means, and the `required` attribute still tells screen readers which fields are required, field by field.

## After: an asterisk explained before the form

```html
<p>Fields marked <span aria-hidden="true">*</span> are required.</p>

<label for="name">Full name <span class="star" aria-hidden="true">*</span></label>
<input id="name" name="name" type="text" autocomplete="name" required>

<label for="email">Email <span class="star" aria-hidden="true">*</span></label>
<input id="email" name="email" type="email" autocomplete="email" required>

<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">
```

This is the W3C technique H90: every required field carries a visible mark, and the line before the first field says what the mark means. The asterisk is hidden from screen readers, which hear "required" from the attribute instead of "star".

## Which option to use

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.

## Implementation decisions

**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 `div`s 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

1. View the form in greyscale and at 200% zoom before typing anything, and check each required field can be told apart by visible text in or beside its label.
2. Inspect every field and check that exactly the fields with a required mark have the `required` attribute, or `aria-required="true"` on custom controls.
3. With a screen reader, Tab through the form and check each required field is announced as required and no optional field is.
4. Submit the form with every unmarked field empty and every marked field filled in, and check the server accepts it; then empty one marked field and check it is rejected.

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.
