Guide · Intermediate
Audit a form for accessibility and reliable delivery
Review labels, groups, keyboard behavior, errors, privacy, server validation, and live delivery as one complete form journey.
- Published
- Last checked
Audit the journey, not the screenshot
A form is successful only when a person can understand it, enter information, recover from a mistake, submit it, and learn what happened next. A clean layout proves none of those things. The useful unit of review is the complete journey from the first instruction to the delivered message or recorded transaction.
Begin on the exact deployed page you intend to publish. Write down the form's purpose, the information it requests, where that information goes, who receives it, how long it is retained, and what the user is promised after submission. If any answer is unknown, record the gap before touching the markup. Accessibility cannot repair a form whose destination or privacy behavior is undefined.
Use realistic but non-sensitive test data. Never put an actual password, payment credential, private health detail, or customer record into a diagnostic submission. If the form reaches a real inbox or service, tell the recipient that the message is a test and arrange to remove it under the site's retention rules.
Inventory every control and action
List each input, select, textarea, checkbox, radio group, upload control, hidden field, and submit action. For every visible control, identify its programmatic name, expected input, required state, and error message. For every hidden value, identify who controls it and whether the server is allowed to trust it.
Prefer native controls because the browser already supplies focus, keyboard, value, validation, and platform accessibility behavior. A styled button remains a button. A generic element with a click handler must recreate an expanding set of behavior and commonly misses keyboard activation, disabled state, or an accessible name.
Check button types explicitly. A button inside a form submits by default. Use a
submit button for the final action and type="button" for controls that only
reveal help, add another row, or change the interface. Confirm that the form has
a real HTTPS action or an implemented script path; a decorative success message
is not delivery.
Check names, labels, and groups
Every field needs a persistent label that describes what to enter. Associate a
label with its control by wrapping the control or matching the label's for
value to the control's unique id. Placeholder text can demonstrate a format,
but it disappears after typing and must not be the only name or instruction.
Inspect the browser accessibility tree as well as the source. The computed name
should be concise and stable. Do not repeat the same long instruction in the
label, description, placeholder, and error. Connect supporting instructions with
aria-describedby only when that relationship adds useful context.
Group related radio buttons or checkboxes in a fieldset with a legend. The legend asks the group-level question; each control's label names its option. This avoids forcing someone to infer the question from a sequence of isolated answers. If the visual design makes a fieldset difficult to style, change the CSS rather than discarding the relationship.
Mark required inputs in text and with the native required attribute where
appropriate. A coloured asterisk alone is ambiguous. Give examples before the
field when format constraints are unusual, and use an appropriate input type and
autocomplete token so browsers can offer the right keyboard and stored
information.
Complete the keyboard path
Reload the page and start with the keyboard. Tab into the form, move through every control, change every value, activate help and disclosure controls, and submit. Then repeat backwards with Shift+Tab. Focus order should follow the meaningful source order, and the focus indicator must remain visible against every background and state.
Use the keys native to each control. Space toggles a checkbox. Arrow keys move within a radio group and many select controls. Enter submits when the form's context makes that expected. Escape closes a modal layer and returns focus to the control that opened it. A custom widget needs the full documented keyboard contract, not merely a keydown listener for Enter.
At 320 CSS pixels, repeat the journey without horizontal page scrolling. Zoom text to 200 percent and check that labels, errors, and buttons are not clipped. If a multi-column form changes to one column, verify that the visual order still matches DOM and focus order. CSS reordering must not create one sequence for the eye and another for the keyboard.
Force every invalid state
Submit the form empty. Enter the wrong format in every constrained field. Try values at the documented length boundary, then one beyond it. Disconnect the network or make the endpoint return an error. Each failure should preserve the user's safe input, identify the affected field in text, explain how to correct it, and avoid reporting success.
Browser validation can provide a useful first layer, but the server must repeat all authoritative checks. Client code can be bypassed, may fail to load, and cannot decide whether a user owns an account or whether a hidden price is real. Treat submitted identifiers, paths, roles, prices, and return URLs as untrusted input.
After an invalid submission, move focus deliberately when doing so helps. A short error summary can receive focus and link to each affected field. Field errors should be associated with their controls, and invalid state should be exposed programmatically. Do not clear the entire form or force a person to rediscover which values were accepted.
Dynamic success and failure messages need an announcement strategy. A status region can announce a short update without stealing focus; an alert is suitable only for urgent interruptions. Test with a screen reader rather than assuming that adding an ARIA attribute proves the message is useful or correctly timed.
Review privacy, abuse, and server behavior
Collect only information required for the stated task. Explain why sensitive or unexpected fields are necessary before the person reaches them. Link to the applicable privacy information near the form and make consent specific when it is genuinely required. A preselected marketing checkbox is not a substitute for an informed choice.
On the server, parse against a bounded schema, reject oversized or unexpected fields, normalize only where meaning is preserved, and encode values before placing them into HTML or logs. Add proportionate abuse controls without making the form impossible for assistive-technology users. Rate limits, honeypots, and server-side heuristics often impose less interaction cost than an inaccessible challenge.
Return a response that distinguishes validation failure, temporary delivery failure, and success. Do not expose stack traces, provider secrets, or internal addresses. Log enough to investigate a failed delivery while avoiding full message bodies and unnecessary personal data. Define retention and deletion for both the destination system and diagnostic logs.
Prove delivery on the deployed form
Submit one marked test through the production-like preview. Confirm the browser shows a truthful pending state, prevents accidental duplicate submission, and recovers when the request fails. Then verify the actual destination: inbox, queue, CRM record, webhook log, or database entry. A 200 response from the page is not evidence that the downstream message arrived.
Check the request in browser tools. Confirm HTTPS, expected method, bounded payload, correct content type, and no sensitive values in the URL. Verify that cross-origin policy, content security policy, redirects, and deployment configuration match the intended host. Test a direct reload of the success or failure route so a client-side transition does not conceal a broken server response.
If submission sends email, verify the authenticated sender, reply path, subject, plain-text alternative, and accessible content. If it creates an account or payment, verify the authoritative provider record and idempotency behavior. Run the same test after promotion because environment variables and endpoint allow-lists can differ between Preview and Production.
Record evidence and remaining limits
Record route, deployment, date, browsers, viewport, input method, assistive technology, test data class, response, and downstream evidence. Keep automatic checks separate from manual results. An axe pass can find detectable violations; it does not prove that instructions make sense, errors are useful, or a message arrived.
Prioritize findings by blocked task, lost data, misleading state, and repeated friction. Fix the smallest causal defect and add a regression at the right layer. A label association belongs in a component test; focus and reflow need a browser journey; delivery needs a real boundary check.
This audit does not certify universal accessibility, legal compliance, or deliverability. It establishes reproducible evidence for the tested form and states what was not covered. Repeat it whenever fields, validation, providers, privacy terms, or deployment configuration change.