In short
An accessible form uses a real label element associated with every input, groups related controls with fieldset and legend, announces errors in text linked to the field they concern, and never relies on placeholder text or colour alone. Most of it comes free from correct HTML — the failures usually come from replacing native controls with custom ones.
Native elements do most of the work
The shortest route to an accessible form is to use the elements the browser already provides.
A real <input>, <select>, <textarea> and <button> arrive with keyboard support, focus handling, assistive-technology semantics, and platform conventions — including mobile behaviours like the correct keyboard appearing.
Most accessibility failures in forms come from replacing these with custom components built from <div>s. If you build a custom control, you inherit responsibility for everything the native one did, and that list is longer than it appears.
Every field needs a real label
Associated properly, either by wrapping the input or by matching for to the input's id.
This does two things: screen readers announce the field's purpose, and clicking the label focuses the input — which is a usability improvement for everyone, particularly on touch.
Placeholder text is not a label. It disappears the moment someone types, so anyone who loses their place has no way to recover it. It is usually too low-contrast to meet requirements. And support for announcing it varies.
Use placeholders for genuine examples — a format hint like +383 44 123 456 — alongside a visible label, never instead of one.
Do not hide labels visually to save space unless you are certain of the alternative. If the design cannot accommodate labels, the design needs revisiting more than the markup does.
Group related controls
Radio buttons and checkboxes belonging to one question need <fieldset> with a <legend>.
Without it, a screen reader announces "Yes" and "No" with no indication of the question. The legend supplies the context that sighted users get from proximity.
This matters most in the places it is most often skipped: consent options, delivery choices, and anything where the answer has consequences.
Help before, errors after
Format requirements go before the field, not after. Telling someone their password needs a number once they have already submitted is a worse experience than telling them beforehand.
Link help text to its field with aria-describedby so it is announced along with the label rather than being encountered separately.
Errors must be text, not only a red border. Colour alone excludes anyone who cannot distinguish it, and conveys nothing to a screen reader.
Each error should sit adjacent to its field, be linked with aria-describedby, and say what is wrong and how to fix it. Mark the field aria-invalid. For a form-level summary, place it at the top, move focus to it on submit, and link each item to the field it concerns.
Announce changes
Anything that updates without a page load needs announcing, or it is invisible to a screen reader user.
Use a live region for validation messages appearing as someone types, for a success confirmation after submit, and for anything appearing or disappearing based on an earlier answer.
Be restrained. A live region announcing on every keystroke is worse than silence — it interrupts constantly and people turn it off.
Use the right input types and autocomplete
type="email", type="tel", type="url", type="number" give mobile users the appropriate keyboard, which is a meaningful reduction in effort.
autocomplete attributes let browsers and password managers fill fields correctly. autocomplete="email", "given-name", "street-address", "one-time-code" — these are standardised and widely supported.
This is one of the highest-value accessibility improvements available, because it removes typing entirely for people who find typing difficult, and it improves form completion for everyone.
Focus and keyboard
Tab order should follow the visual order. If it does not, the DOM order is wrong — fix that rather than overriding with tabindex.
Focus must be visible. Style it rather than removing it, and use :focus-visible so a ring appears for keyboard users without showing on every mouse click.
On submission with errors, move focus to the summary or to the first invalid field. Leaving focus where it was means a screen reader user has no idea anything happened.
Never trap focus in a field, and never move focus while someone is typing.
Required, optional, and honesty
Mark required fields in text as well as with an asterisk, or explain the asterisk. Use the required attribute so it is announced.
Better: if most fields are required, mark the optional ones instead — it is less visual noise and clearer.
Best of all, ask for less. Every field is an obstacle, and the most accessible field is the one you removed because you did not actually need it.
Testing it
Tab through with the mouse untouched. Reach every field, understand where you are, submit, and reach the errors.
Zoom to 200% and confirm nothing overlaps or is cut off.
Use a screen reader for five minutes. Are labels announced, are errors announced, does anything read as an unlabelled edit field?
Submit it empty and see what happens. This single test finds most error-handling failures.
If you have a form that people abandon and you are not sure why, book a call — it is frequently something on this list.
Common questions
Why isn't placeholder text a substitute for a label?
It disappears as soon as someone types, leaving anyone who loses their place with no way to recover what the field was for. It is usually too low in contrast to meet requirements, and support for announcing it to assistive technology varies. Use it for format examples alongside a visible label.
How should form errors be announced?
As text adjacent to the field, linked with aria-describedby and with the field marked aria-invalid — never as a red border alone, which conveys nothing to a screen reader and excludes anyone who cannot distinguish the colour. Say what is wrong and how to fix it, and move focus to the error on submit.
When should I use fieldset and legend?
For any group of radio buttons or checkboxes answering one question. Without them a screen reader announces the options with no indication of the question being asked, which matters most on consent choices and anything with consequences — exactly where it is most often skipped.
Do autocomplete attributes help accessibility?
Substantially. Standard values like email, given-name, street-address and one-time-code let browsers and password managers fill fields correctly, which removes typing entirely for people who find it difficult — and improves completion rates for everyone.
How do I test whether a form is accessible?
Tab through it without touching the mouse and confirm you can reach every field, understand where you are, submit, and reach the errors. Zoom to 200% to check nothing overlaps. Try a screen reader for five minutes. And submit the form empty, which finds most error-handling failures on its own.
