Accessible form structure
Write useful instructions
Place concise help where people encounter it and connect control-specific instructions with aria-describedby when needed.
Tell people the rules before they submit. An error message should never be the first place someone learns that a password needs 12 characters or that only PNG files are accepted.
Put general instructions near the top of the form. Put field-specific help right beside the field it belongs to:
<label for="username">Username</label>
<p id="username-help">Use 3–20 letters, numbers, or hyphens.</p>
<input
id="username"
name="username"
aria-describedby="username-help"
minlength="3"
maxlength="20"
pattern="[A-Za-z0-9-]+"
>
The paragraph is visible to everyone. aria-describedby does the extra work for screen reader users. It points at the paragraph’s id, so when the input gets focus the reader announces “Username, edit text, Use 3 to 20 letters, numbers, or hyphens.”
Without that attribute, a screen reader user hears the label and starts typing, and only finds the help text if they go looking for it.
Several descriptions
aria-describedby accepts more than one id, separated by spaces:
<input id="username" aria-describedby="username-help username-error">
This is how you keep the help text and add an error message later, without losing either. We’ll use this in the lesson on error messages.
Be concrete
Compare these two:
- “Enter a valid value”
- “Use 3–20 letters, numbers, or hyphens”
The first one explains nothing. The second tells the person exactly what will pass. Write the second kind, and keep it to one sentence.
Where help must not live
Don’t put an essential instruction only in a tooltip or a placeholder. A tooltip needs a hover, which doesn’t exist on a phone and is hard to reach with a keyboard. A placeholder vanishes as soon as typing starts.
Both are fine as extras. Neither can be the only place the rule appears.
Match the server
The help text is a promise. If the page says “up to 20 characters” and the server rejects anything over 16, you built a trap. People follow the instructions and still fail.
Keep the numbers in one place and use them in both the HTML attributes and the server check. When you change the limit, change it everywhere.
Here is a test I like. Read the form without touching it. For every field, can you predict what’s required and what format passes? If you have to guess anywhere, move the missing instruction next to that field.
Lesson completed