Skip to content

HTML Forms

Modern, accessible, autofill-ready form patterns using the full web platform — no library dependencies.

I need to...

I need to... Guide Summary
Structure a form with correct semantics, labels, and grouping Form Structure & Semantics Wrap all controls in
, use fieldset+legend for groups, always associate
Pick the right type, inputmode, and enterkeyhint for mobile keyboards Input Types & Modes Use type="text" + inputmode="numeric" for card numbers and ZIP codes — never type="number" which strips leading zeros and adds spinners. Set enterkeyhint on every field in multi-step forms. Pattern performs a full match; allow spaces and international characters users naturally type.
Wire autocomplete tokens for address, payment, sign-in, sign-up Autocomplete & Autofill Add autocomplete to every input, select, and textarea. Autofill requires a stable name/id, a wrapper, a submit button, and a recognised token. Use autocomplete="username" on sign-in email inputs so password managers link them to stored credentials. Never use autocomplete="off" on password fields.
Style fields that the browser has autofilled Autofill Visual Feedback Use box-shadow inset to simulate background-color on autofilled inputs — background-color is blocked by the browser's security model. Always include :autofill:focus-visible with an explicit outline; never remove focus indicators from autofilled fields. Progressive enhancement — no Firefox support.
Show validation errors only after user interaction Native Validation Use :user-invalid (not :invalid) so errors appear only after the user has interacted with a field. Bridge to AT with aria-invalid="true" via JS on blur and submit — :user-invalid is CSS-only and invisible to screen readers. Clear setCustomValidity() on the input event or the custom message sticks after correction.
Make inputs and textareas auto-grow to fit content Field Sizing Use field-sizing:content as progressive enhancement — Chrome/Edge 123+, Safari 26.2+, not Firefox. Set min-inline-size on inputs (prevents zero-width collapse when empty) and fixed width on textareas (prevents jarring horizontal shift). Override width:100% global CSS with width:auto. Feature-detect with @supports.
Style a select on-brand without building a JS widget Styling Native Select appearance:base-select is Chrome/Edge 135+ only; degrades gracefully to OS native on other browsers. Apply to both the element AND ::picker(select) or the picker retains OS styling. Grid picker layouts do not give 2D keyboard navigation — Up/Down arrows only. Guard all animations with prefers-reduced-motion.
Embed icons or descriptions inside option elements Rich Media Input Use appearance:base-select + HTML in