♿
EPISODE 03
label · fieldset · errors · keyboard · focus management
Accessible Forms
Forms are the most accessibility-critical part of your app. Pair labels properly, group with fieldset, announce errors clearly, and manage focus.
formlabelfieldseterrorsfocus
Duration
⏱ About 1.5 hours
Level
📊 Intermediate
Prerequisite
🎯 a11y-02
OUTCOME
Forms that any keyboard or screen-reader user can complete
What you'll learn
- 1Pair every input with a real <label>
- 2Group related inputs with <fieldset> + <legend>
- 3Show validation errors with aria-describedby and aria-invalid
- 4Move focus to the first error on submit
1. Real Labels (not Placeholders)
html
<!-- Bad: placeholder is not a label -->
<input placeholder="Email">
<!-- Good: explicit label -->
<label for="email">Email</label>
<input id="email" name="email" type="email">
<!-- Or wrapped -->
<label>
Email
<input name="email" type="email">
</label>2. fieldset for Groups
html
<fieldset>
<legend>Shipping address</legend>
<label>Street <input name="street"></label>
<label>City <input name="city"></label>
</fieldset>
<fieldset>
<legend>Newsletter</legend>
<label><input type="radio" name="news" value="weekly"> Weekly</label>
<label><input type="radio" name="news" value="monthly"> Monthly</label>
</fieldset>3. Error Messages
html
<label for="pw">Password</label>
<input id="pw" type="password" aria-describedby="pw-help pw-err" aria-invalid="true">
<span id="pw-help">At least 8 characters.</span>
<span id="pw-err" role="alert">Password too short.</span>💡
Show errors near the input, link them with aria-describedby, and announce them with role="alert".
4. Focus on Submit Error
javascript
function onSubmit(e) {
e.preventDefault();
const errors = validate(form);
if (errors.length) {
const first = form.querySelector(`[name="${errors[0].name}"]`);
first?.focus();
return;
}
// ... submit ...
}Example code / lecture materials
All lecture materials and example code are openly available on GitHub.
View on GitHub ↗