Autocomplete Attribute and Validation
What does the autocomplete attribute have to do with validation? More than any other attribute: the cheapest validation error is the one that never happens because the browser filled the field correctly. Correct tokens let browsers and password managers fill names, addresses, emails, phone numbers, card details and one-time codes accurately, which removes typos before any rule runs — and WCAG 1.3.5 requires them for fields that collect information about the user. Wrong or missing tokens do the opposite: a card number filled into a phone field, a billing postcode in the delivery address, a password manager saving a one-time code as a password. This recipe chooses tokens for common form fields, scopes them with sections, handles the cases where autofill should be discouraged, and makes sure autofilled values still go through the Constraint Validation API like typed ones.
When Autocomplete Tokens Matter Most
Every field that collects personal information should have a token. They matter most when:
- Forms are long or repetitive — checkout, registration, applications — where autofill saves the most effort and prevents the most typos.
- Users are on mobile, where typing an address or card number is slow and error-prone.
- Users have motor or cognitive disabilities, for whom autofill is an assistive technology; this is why WCAG 1.3.5 Identify Input Purpose is a Level AA requirement.
- Password managers are involved — sign-in, sign-up, password change and one-time code flows depend on the right tokens to offer, save and generate credentials.
Tokens complement type and inputmode rather than replacing them: type="email" drives validation and the keyboard, autocomplete="email" drives filling. Both belong on the field, as the HTML5 input types and attributes topic describes.
Minimal Working Autocomplete Setup
<form id="checkout" novalidate>
<fieldset>
<legend>Contact</legend>
<label for="name">Full name</label>
<input id="name" name="name" autocomplete="name" required>
<label for="email">Email address</label>
<input id="email" name="email" type="email" autocomplete="email" required>
<label for="tel">Phone number <span class="optional">(optional)</span></label>
<input id="tel" name="tel" type="tel" autocomplete="tel">
</fieldset>
<fieldset>
<legend>Delivery address</legend>
<label for="ship-line1">Address line 1</label>
<input id="ship-line1" name="shipping.line1" autocomplete="shipping address-line1" required>
<label for="ship-city">Town or city</label>
<input id="ship-city" name="shipping.city" autocomplete="shipping address-level2" required>
<label for="ship-postcode">Postcode</label>
<input id="ship-postcode" name="shipping.postcode" autocomplete="shipping postal-code" required>
<label for="ship-country">Country</label>
<select id="ship-country" name="shipping.country" autocomplete="shipping country" required>…</select>
</fieldset>
<fieldset>
<legend>Payment</legend>
<label for="cc-name">Name on card</label>
<input id="cc-name" name="ccname" autocomplete="cc-name" required>
<label for="cc-number">Card number</label>
<input id="cc-number" name="cardnumber" inputmode="numeric" autocomplete="cc-number" required>
<label for="cc-exp">Expiry date (MM/YY)</label>
<input id="cc-exp" name="cc-exp" inputmode="numeric" autocomplete="cc-exp" required>
<label for="cc-csc">Security code</label>
<input id="cc-csc" name="cvc" inputmode="numeric" autocomplete="cc-csc" required>
</fieldset>
<button type="submit">Pay</button>
</form>
// Autofilled values go through exactly the same validation as typed ones.
const form = document.querySelector<HTMLFormElement>("#checkout")!;
let scheduled = false;
function revalidate(): void {
scheduled = false;
for (const el of form.querySelectorAll<HTMLInputElement | HTMLSelectElement>("[name]")) {
runCustomRules(el); // Luhn, expiry, postcode by country…
if (el.getAttribute("aria-invalid") === "true" && el.checkValidity()) {
el.removeAttribute("aria-invalid"); // withdraw errors the fill fixed
}
}
}
// Autofill fires a burst of input/change events; validate once after it settles.
for (const type of ["input", "change"] as const) {
form.addEventListener(type, () => {
if (!scheduled) { scheduled = true; requestAnimationFrame(revalidate); }
});
}
form.addEventListener("submit", (e) => {
revalidate();
if (!form.reportValidity()) e.preventDefault();
});
The shipping prefix scopes the address tokens to the delivery block, so a browser holding separate billing and shipping addresses fills each block with the right one. Coalescing the autofill burst into one validation pass prevents rules that depend on several fields — a postcode that depends on the country — from judging a field before its neighbour has been filled, the problem covered in validating autocompleted address fields.
Autocomplete Token Reference
| Purpose | Token | Notes |
|---|---|---|
| Full name / parts | name, given-name, family-name |
Prefer one name field where possible |
email |
With type="email" |
|
| Phone | tel (tel-national, tel-country-code) |
With type="tel" |
| Address | street-address or address-line1..3, address-level1..2, postal-code, country |
Prefix with shipping / billing |
| Organisation | organization, organization-title |
— |
| Birthday | bday or bday-day, bday-month, bday-year |
Split fields for dates of birth |
| Card | cc-name, cc-number, cc-exp (or cc-exp-month/cc-exp-year), cc-csc |
Browsers may require HTTPS |
| Sign-in | username, current-password |
Lets managers fill saved credentials |
| Sign-up / change | new-password |
Triggers password generation |
| One-time code | one-time-code |
SMS code autofill on mobile |
| Repeated blocks | section-<name> prefix |
e.g. section-guest2 email |
| Discourage filling | off |
Browsers may ignore it for credentials |
Verification Steps
import { test, expect } from "@playwright/test";
test("every personal-data field has a valid autocomplete token", async ({ page }) => {
await page.goto("/checkout");
const missing = await page.evaluate(() =>
[...document.querySelectorAll("input[name], select[name]")]
.filter((el) => !(el as HTMLInputElement).autocomplete || (el as HTMLInputElement).autocomplete === "on")
.map((el) => (el as HTMLInputElement).name),
);
expect(missing).toEqual([]);
});
Edge Cases and Failure Modes
autocomplete="off" on sign-in fields. Browsers largely ignore it for username and password fields, and trying to block password managers fails WCAG 3.3.8 Accessible Authentication. Use the correct credential tokens instead.
Made-up token values. Values like autocomplete="nope" to defeat autofill are invalid tokens; they fail axe-core’s autocomplete-valid rule and behave inconsistently. Use off where filling genuinely makes no sense (a search-within-results box, a CAPTCHA answer).
Autofill that bypasses your events. Some engines fill fields without dispatching input. Validate on submit regardless, and consider the :autofill animation hook as a backup signal, described in the address guide linked above.
Styling autofilled fields. Browsers paint autofilled inputs with their own background, which can hide your error styling. Keep error indicators that do not rely on background colour — border, icon and text — so an autofilled but invalid value is still visibly wrong.
Designing Fields So Autofill Can Succeed
Tokens only work if the field structure matches what browsers store. Browsers keep one full name, one email, one phone and a small set of address parts per profile; forms that deviate from that shape force autofill to guess, and guesses produce validation errors. A few structural choices make filling reliable. Use one name field rather than first, middle and last unless you truly need the parts. Use street-address in a textarea or address-line1 and address-line2 — not three lines labelled arbitrarily. Put the country selector’s option values as ISO codes and its text as localised names, because browsers match either. Avoid splitting a phone number into several inputs, which most browsers cannot fill. And keep the order of fields conventional for the locale, since some engines use field order as a heuristic when tokens are ambiguous.
Validation rules must accept whatever shape autofill produces. A browser may fill a phone number with an international prefix and spaces, a postcode in lower case, or a name with a trailing space. Normalise before validating — trim, adjust case, strip formatting — so a correct autofilled value never fails a rule that a human typing carefully would pass. The normalisation habits are the same as those in transforming and coercing form input with Zod: accept generously, normalise once, then validate strictly.
Auditing Tokens Across a Product
Autocomplete tokens decay as forms change: a field is renamed, a new block is added by copy-paste, a component library wraps inputs and drops the attribute. A lightweight audit in CI keeps them honest. The Playwright check above fails when a named field has no token; axe-core’s autocomplete-valid rule fails when a token is misspelled or invalid; and a short review list of the product’s forms, with the expected token per field, catches semantic mistakes such as email on a “friend’s email” field that should not be filled with the user’s own address. Run the audit on every form, not just checkout, because sign-up, profile and support forms collect the same personal data.
One-Time Codes and Credential Fields
Credential flows depend on tokens more than any other form. A sign-in form uses username and current-password, so managers fill saved credentials. A sign-up or password-change form uses new-password, so managers offer a generated password and save it afterwards; if the page asks for the current password too, give that field current-password so the manager does not overwrite the wrong one. A verification step uses one-time-code with inputmode="numeric", which lets mobile platforms offer the code from an incoming SMS with one tap — and validation for that field should accept exactly what the platform inserts (digits only, no spaces) rather than enforcing a pattern with separators. These tokens are the difference between a flow that password managers handle perfectly and one that trains users to reuse weak passwords; the password side is covered in password validation patterns.
Frequently Asked Questions
How does the autocomplete attribute relate to form validation?
Correct tokens let browsers and password managers fill fields accurately, which prevents typos before any validation rule runs. Filled values must still pass the same validation as typed ones.
Is autocomplete required for accessibility?
Yes, for fields collecting information about the user. WCAG 2.2 success criterion 1.3.5 Identify Input Purpose (Level AA) requires programmatically identifiable purpose, which the autocomplete tokens provide.
How do I stop autofill mixing billing and shipping addresses?
Prefix address tokens with shipping or billing, for example autocomplete="shipping postal-code". For other repeated blocks, use a section-name prefix.
Should I use autocomplete="off" on password fields?
No. Browsers mostly ignore it for credentials, and blocking password managers harms security and accessibility. Use current-password on sign-in and new-password on sign-up and password change.
Related Guides
- HTML5 Input Types & Attributes — type and inputmode alongside autocomplete.
- Validating Autocompleted Address Fields — running dependent rules after a fill.
- Payment Card Validation — the card fields these tokens fill.
- WCAG 3.3.7 Redundant Entry Checklist — avoiding re-entry of information.