Every control needs a label
The programmatic label is what screen readers announce. Three valid patterns:
<label for="id">Email</label> <input id="id">— best.<label>Email <input></label>— wrapping, also fine.aria-label="Email"— only when a visible label is impossible.
Placeholders are not labels.
Group related controls
Radios and checkboxes belong in a <fieldset> with a <legend>. Screen readers announce the legend before each option.
Errors must be programmatic
- Move focus to the first invalid field, or expose a summary with
role="alert". - Associate the error message with the field via
aria-describedby. - Never rely on color alone — include an icon and text.
Autocomplete tokens
Use the autocomplete attribute on all common fields (email, given-name, family-name, street-address, postal-code, cc-number). WCAG 1.3.5 requires it, and password managers depend on it.
Required indication
Mark required fields visually and programmatically (required or aria-required="true"). An asterisk alone is not enough.
