Lesson 5 of 30
A red border and small red text under a field is a purely visual error signal — invisible to a screen reader unless it's also wired up programmatically. Forms are where accessibility bugs compound fastest, and where the fix pattern is fully specified.
13 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 3
A form field uses only placeholder text ("Full name") instead of a `<label>`. Why is this considered a real accessibility bug rather than a minor style choice?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
An accessible form field needs three things working together, and each is a real, specific mechanism, not a general good-practice gesture:
<label for="...">, not just visual adjacency. A label sitting next to an input in the layout means nothing to assistive technology unless it's programmatically tied to that input via for/id (or by wrapping the input inside the <label>). A placeholder is not a substitute: placeholder text disappears the instant the user types, and isn't announced with the same reliability as a real label — it should describe an example value, never stand in for the field's name.<fieldset> and <legend> for grouped fields. A set of radio buttons answering one question ("Preferred contact method") needs a <fieldset> wrapping the group and a <legend> naming the question, so a screen reader announces the group's purpose once before reading the individual options — without it, a user tabbing through radio buttons hears "Email, Phone, Text" with no idea what question they're answering.aria-invalid="true" on the field marks it as currently failing validation, and aria-describedby pointing at the actual error message text makes that message get announced when the field receives focus — the same field-level pattern aria-describedby provides for hint text, just wired to error content this time.<label for="email">Email</label>
<input
id="email"
type="email"
aria-invalid="true"
aria-describedby="email-error"
/>
<p id="email-error" role="alert">
Enter a valid email address.
</p>
Three things happen together here: the label is really connected via for/id, aria-invalid="true" tells assistive technology this specific field is currently in an error state, and aria-describedby="email-error" links the field to the actual error text so it's announced right after the field's name when focus lands there — not just visible somewhere on the page. role="alert" on the error paragraph turns it into a live region, so if the error appears after the field already has focus (e.g. on blur, or after a failed submit while focus stays put), it's announced proactively instead of requiring the user to go looking for it. Live regions get their own deeper treatment in a later lesson — the pattern here is the specific instance that matters most: form validation.
aria-invalid and aria-describedby alone (with no visual change) fail low-vision users who aren't using a screen reader. The accessible pattern requires both together, not either one.<fieldset>/<legend> matters most exactly when it's easiest to skip — a short, seemingly self-explanatory group of radio buttons or checkboxes. The individual option labels ("Yes," "No") mean nothing without the question they're answering, and that question is exactly what gets lost without a real <legend>.aria-describedby for an error only helps if it fires when the user needs it, not just when the page loads. Adding the attribute once at initial render, before any error exists, and never updating aria-invalid/aria-describedby when a real error appears is a common half-implementation that looks correct in the initial markup and fails at the moment it actually matters."Build a form field's error state so a screen reader user actually knows validation failed" is a standard practical exercise, and the strong answer names the full connected pattern — real label, aria-invalid, aria-describedby pointing at the message, and a live region or role="alert" so it's announced proactively — rather than stopping at "add ARIA to the error text."