HTML & CSS / Editorial solution guide
Diagnose inaccessible labels, errors, and focus
Follow the complete form interaction to identify missing names, broken associations, hidden focus, and feedback that cannot support correction.
Read-only knowledge base · No public comments
Recognize the symptoms
A field is announced without a useful name, clicking nearby text does not focus it, keyboard focus disappears, or an error is visible but cannot be connected to its control. A form can look polished while these interactions fail.
A placeholder may be the only instruction, repeated ids may connect a label to the wrong field, or a parent may clip an otherwise valid focus outline.
Understand the likely causes
- Visual proximity does not create a label association. Styling a div does not make it a native button, and removing outlines does not remove the need to show focus. Error color alone cannot explain what went wrong.
- Dynamic behavior can also diverge from markup: a hidden panel may retain focusable descendants, or an application may change an error message without updating its association or state.
1. Reproduce the complete interaction
Use synthetic values and navigate with Tab, Shift+Tab, and each native control’s expected keys. Record where the user loses the ability to identify, activate, correct, or leave a control. Inspect the browser’s accessibility tree for the computed role, name, description, and state. A visual label and an accessible name should normally agree, so speech input and visual understanding can refer to the same control. An automated scan is useful evidence but cannot judge whether the name explains the task or whether focus movement makes sense.
2. Repair the native label relationship
Give each control a unique id and connect the visible label’s for attribute to it exactly. A name attribute serves submission and does not replace that id relationship. Keep persistent labels instead of relying on placeholder text. Use fieldset and legend where a shared question is required for a group of choices. The example pairs an explicit label with an email field and separate helper text. Avoid adding aria-label as a blanket repair because it can override an existing visible label and create a new mismatch. Prefer the simplest correct native relationship.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Label repair</title>
</head>
<body>
<main><h1>Contact form</h1><form><label for="email">Email address</label><input id="email" name="email" type="email" aria-describedby="email-help"><p id="email-help">Use an address you can access.</p><button type="button">Local preview</button></form></main>
</body>
</html>
The email field has a visible label and connected help.
The explicit id-for pair supplies the native name, and describedby adds help without replacing it.
3. Restore focus visibility and unclipped access
Remove unjustified outline resets or provide a strong replacement with enough separation and contrast. Inspect ancestor overflow, fixed overlays, and sticky regions that may conceal the focused control. Test actual keyboard movement after the change. Do not use positive tabindex values to patch a broken visual order; repair source and layout order instead. The complete example gives the field and button an explicit focus-visible outline without suppressing all other browser focus behavior. Check every relevant theme and zoom level, because a visible blue ring on one background may disappear on another.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Focus repair</title>
<style>
input, button { font: inherit; padding: .6rem; margin: .5rem; } :is(input, button):focus-visible { outline: 3px solid #174e9a; outline-offset: 3px; }
</style>
</head>
<body>
<main><h1>Focus check</h1><form><label for="name">Contact name</label><input id="name" name="name"><button type="button">Continue preview</button></form></main>
</body>
</html>
Keyboard navigation visibly identifies the active control.
Keyboard focus receives a distinct outline. Spacing helps avoid clipping but the full ancestor chain still requires inspection in a real component.
4. Connect errors and verify recovery
Display a specific correction message, associate it with the field, and expose invalid state when that state actually applies. Do not mark every untouched field invalid immediately without an intentional validation design. For dynamic feedback, review timing, announcements, any error summary, and focus management with the relevant assistive technology. Preserve entered values where safe and tell the truth about server outcomes. A CSS red border can reinforce an error but cannot provide its explanation or implement live announcements. Test correction and successful continuation, not only the moment the error first appears.
Verify the fix
Click each label, inspect the computed name and description, complete the form by keyboard, trigger a synthetic error, correct it, and leave every component without a trap. Repeat at high zoom and in the supported assistive-technology setup. Confirm that no required information depends only on color, hover, or a disappearing placeholder.
Keep it from recurring
- Keep native form patterns in reusable components, enforce unique ids, and review labels and states when fields are dynamically repeated. Include keyboard and error-recovery journeys in routine acceptance checks.