Forms that work
The form checks we run, and the one you have to run yourself
A contact form that quietly stops working is the most expensive fault a small business can carry, because it looks exactly like nobody being interested. Here is what the audit reads from the outside, and the part only you can test.
Why a broken form is worse than a slow one
A form that has stopped working does not announce itself. Nobody rings to say the message never arrived. The visitor types their question, presses send, sees a thank-you and waits. You see a quiet month and conclude the market has gone quiet with it.
The ranking reflects that. Findings naming form labels, a form index, a CSRF token, missing contact information or a JavaScript console error are classed as blocking conversion and weighted 2.4 — behind only the class that stops a page being found at all, at 3.0. That is weighted 1.4 again for sitting on a contact page, against 0.5 on a privacy page.
Labels are not decoration
A label tells a screen reader which box the visitor has landed in, and tells the browser's autofill that a field wants a name, an email or a phone number. Without one the field is announced as nothing and the visitor guesses. A form carrying no label element at all is a warning, in the code's own words: label every field, because screen readers and autofill both depend on it.
Two restraints stop that firing wrongly. Fields of type hidden, submit and button do not count as fields, so a one-button logout or a search stub is not mistaken for a form full of unlabelled inputs. And once one form on a page is reported the check stops: three identical lines about one page is noise, not detail. Each finding names the page it came from, so it reads as the form on your /contact page.
Where the form submits, and what leaves the browser
Every form is recorded with its action and its method, and both appear in the report. Two things there become findings. A form on an HTTPS page whose action begins http:// is a warning: the contents travel over an open connection. A form with no token field — an input named csrf, token or _token — is a warning for missing CSRF protection.
Two more facts are counted rather than raised. Inputs with no type attribute produce an informational finding. Inputs with no name are counted and printed with no finding attached, because a script may set the name later — but a control without a name is not a successful control under the HTML standard, so the browser leaves it out of the submission entirely. A count above zero is read by hand before the report goes out.
The submit button that stopped working
Most silent failures are not in the markup, so the audit opens the site in a real headless Chrome and watches. JavaScript errors thrown during load are reported with the reason they matter, again in the code's own words: errors thrown during page load can stop later scripts running, which is how add-to-cart and form submit buttons silently stop working.
That pass counts the forms in the page the browser actually built rather than the file the server sent, so a form injected by a script is seen. Requests the site makes to itself and does not get are reported too. Failures caused by our own machine are not: a third-party request blocked by DNS or by a tracker blocker on the auditing computer says nothing about your site.
The one test we will not run for you
The audit never submits your form. Every check above reads what the page already hands a visitor; posting to it would put a fake enquiry in your inbox and write to your systems. The one unlinked address fetched is a random URL that cannot exist, to see what an unknown path returns — which matters here, because if unknown addresses come back 200 instead of 404, nothing can tell a live destination from a dead one.
So the last test is yours, and it takes five minutes. Send yourself a message through your own form, from a phone on mobile data rather than the office network. Check it arrives, check the spam folder, and check the address it lands in still belongs to somebody who works there. A form pointing at a departed colleague's mailbox passes every check on this page and still loses the enquiry.
What the engine checks here
Each of these is a rule in the code, not a category heading.
- A form with no label elementRaised as a warning on the page it was found on, once per page. Forms whose only controls are hidden, submit or button fields are skipped, so a logout stub or a search box is not counted as an unlabelled form. The rendered pass separately runs axe-core against the WCAG 2.0 and 2.1 A and AA rules, which is where a label that exists but is not attached to its field is caught.
- Whether the contact page has a form at allThe crawl classifies a page as a conversion page from its URL segment — contact, enquiry, request, get-started, appointment and similar — and a conversion page with no form is a warning. The stated impact: a contact page with no form asks the visitor to do the work of opening their mail client, which most will not.
- Where the form posts, and by which methodThe action and method are read from every form and recorded, the method defaulting to GET where none is set. An action beginning http:// is reported as a warning: the submission leaves the encrypted connection, and browsers increasingly refuse to send it.
- A CSRF token in the formDetected from an input whose name contains csrf, token or _token. None present is a warning. The detection is name-based, so a framework using a different naming convention can be missed — one of the reasons every finding is checked by hand before a report goes out.
- Fields with no type, and fields with no nameBoth are counted across the page. Missing type raises an informational finding. Missing name is reported as a count and nothing more, but it is the count worth reading: a control with no name is not included in what the browser submits, so whatever the visitor typed there never leaves their machine.
- Password fields and autocompleteA password input with no autocomplete attribute raises an informational finding, recommending current-password or new-password. It is what lets a password manager fill the field correctly instead of the visitor abandoning a login they cannot complete.
- What an unknown URL returnsA random path that cannot exist is requested with a ten-second timeout. Anything other than 404 is a warning. A 404 that returns a bare server error — under 600 characters, with no link home, back or to search — is informational, because a dead end with no way onward loses a visitor who was already looking for you.
- Runtime errors and failed requestsConsole errors thrown while the page loads are a warning, as are failed requests to the site's own domain. Third-party requests that failed with a DNS or blocked error are excluded by name — ERR_NAME_NOT_RESOLVED, ERR_BLOCKED_BY_CLIENT and their siblings — because those are the auditing machine's own blocking, not your site.
Questions
Do you fill in or submit my form to test it?
No. Every check reads what your page already sends to any visitor. Submitting the form would create a real enquiry in your inbox and write data into your systems, and this engine reads rather than writes. The checks that do send unsolicited traffic live in a separate module that stays switched off unless there is written authorisation for that specific domain. Confirming that a submission actually arrives is the one step we ask you to do yourself, and it takes about five minutes.
Our fields use placeholder text instead of labels. Is that a problem?
The label finding is still raised, and the presence of placeholders is recorded as a separate fact rather than accepted as a substitute. A placeholder disappears the moment someone types, so anyone interrupted mid-form loses the only clue about what the box was for, and it does not reliably give autofill or a screen reader what a label gives them. WCAG 2.1 success criterion 3.3.2 asks for labels or instructions wherever input is required.
Our form is an embedded widget from another service. Will it be checked?
Partly. The rendered pass reads the page after the JavaScript has run, so a form injected by a script is counted along with everything else on the page. A form that lives inside a third-party frame is a separate document the checks do not read into, so the field-level results there are absent rather than passing. Where that happens the report says so, because recording an unrun check as a pass is the same mistake as recording it as a failure.
Sources
Public and checkable. Nothing here rests on a number we cannot point at.
- WCAG 2.1 — Understanding SC 3.3.2 Labels or Instructions
- HTML Standard — naming form controls, and what makes a control submittable
- MDN — the label element
- MDN — the autocomplete attribute
- OWASP — Cross-Site Request Forgery Prevention Cheat Sheet
- RFC 9110 — 404 Not Found
- This engine's audit of this website, published in full
This is one of fifteen categories. You can read a real report this engine produced on this very site — including the findings it raised against us — or ask for an audit of yours.