A form fights the person typing in it when the markup says one thing about a field and the person needs another: a phone shows a full keyboard for a code made of digits, a password manager cannot tell which box is the password, a paste is cancelled, or a label vanishes the moment someone starts to type. A component fights its readers in a different way, because the data that arrives in production is stranger than the sample a developer typed in: a name with no spaces, an empty value, a number with too many digits, a list that is far longer than the design. Both families of mistakes pass a normal test run. This guide lists the ones that recur, what each costs the visitor, and a check that can fail.
Wrong type or input mode: the keyboard that does not fit
A mobile browser picks its on-screen keyboard from hints in the markup. The inputmode attribute describes what is expected, and MDN lists values such as numeric, tel, email and url, each asking for a keyboard that suits that data (MDN, inputmode). The same page adds that an input which requires an email address should usually use type="email" rather than the attribute alone, and the same goes for phone numbers and web addresses.
The mistake runs in both directions. The first direction is a plain text field for an email, which gives the visitor a general keyboard where the at sign sits on a second page. The second is the field that holds only digits and is marked type="number". MDN says that type is meant for values you count with, and calls it a poor fit for things that merely consist of digits, naming postal codes and card numbers; it also warns about accidental increments and about missing feedback when someone types something non-numeric (MDN, number input). A verification code behaves like a card number here: you never add one to it. The suggested replacement is a text field with a numeric input mode and a pattern that limits the characters.
Counting is the exception. Seats, items or an age really are quantities, and a number field with lower and upper bounds suits them. Flagging those would only teach the team to ignore the review.
Autocomplete tokens: the password manager cannot guess
The HTML Standard defines named autofill tokens for credentials. The current password uses current-password, a new one uses new-password, the account name uses username, and a code sent to confirm identity uses one-time-code (HTML Standard, autofill). MDN explains why the distinction matters: the new-password token lets the browser avoid filling an old password into a creation form and offer help in making a strong one, and the one-time-code token covers codes that arrive by text, email or an authenticator app (MDN, autocomplete).
Two traps follow. First, switching autocomplete off on a login field is advice many developers remember from old tutorials. MDN notes that in most modern browsers it will not stop a password manager from offering to save or fill, and that browsers may ignore it on login fields for exactly that reason, so the attribute buys nothing except confusion. Second, the right token on the wrong field is as bad as none, because a manager that sees a new-password token on a sign-in form will not offer the stored password. The web.dev guidance for sign-in forms recommends autocomplete="username" for the email field, along with the matching current-password or new-password token on the password field (web.dev's guide to sign-in forms).
This is also an accessibility matter. Under WCAG 2.2, the rule numbered 1.3.5 (conformance level AA) asks that the purpose of fields that collect information about the user be programmatically determinable, and the understanding document lists autocomplete attributes as a sufficient technique and incorrect values as a failure (WCAG 2.2, Identify Input Purpose). Search boxes and coupon boxes are not credentials, so switching autocomplete off there is harmless and not worth a finding.
Blocked paste and placeholder labels
Cancelling the paste event on a password field is a mistake that looks like security. Someone whose passwords live in a manager frequently pastes them in, and a blocked paste forces that person to retype something they chose not to memorise. WCAG rule 3.3.8, Accessible Authentication (Minimum), also level AA, describes preventing paste into login fields as a failure unless another route exists, and says that scripts which block password-manager entry can fail it as well (WCAG 2.2, Accessible Authentication). The web.dev article does not take up the paste question, and the MDN page for password inputs does not mention it, so this rests on the WCAG text.
Placeholders are the other quiet offender. The web.dev guidance says plainly not to use placeholders as labels, because people forget what the box was for once they begin typing (web.dev). Keep a visible label above the field and let the placeholder show an example format, if it shows anything.
Autocorrect and capitalisation belong in the same family, with a caveat. MDN says the autocapitalize attribute affects virtual keyboards and voice input, not a physical keyboard, and that it has no effect on url, email or password inputs, where capitalisation is never switched on (MDN, autocapitalize). So an email field with the right type needs no extra attribute, while a plain text field that holds a code or a handle should say autocapitalize="off". Sources for the autocorrect attribute were not read for this guide, so it is not discussed beyond the mention.
A disabled submit button that never explains itself
When a submit button stays inert until every field passes, the visitor taps it and never learns which box is wrong. A kinder pattern leaves the button live and explains the gaps once the visitor taps it. This one comes from experience of how such forms behave, not from a specification, so treat it as a design rule and not a cited fact. Locking the button during the network call, to stop a double send, is another matter and is fine.
The data side: stress a component with awkward values
Components are usually shown with tidy sample data. The problems begin when production data differs, and the useful move is to decide the awkward values in advance and feed them in one at a time. For text, the list that tends to find bugs is short:
- an empty string;
- one very long word with no space, such as a pasted URL or a made-up compound name;
- text with a newline in the middle;
- an emoji sequence joined by the zero-width joiner, and letters followed by combining marks, which are wider or taller than the characters around them;
- right-to-left text from Hebrew or Arabic;
- text that looks like markup.
For numbers: zero, a negative value where the type allows one, a decimal where whole numbers are expected, and a value with many more digits than the design assumed. For lists: empty, one item and a very large number. For optional props: left out entirely.
Each of these breaks something specific. A long unbroken word overflows its box, because there is no place to wrap. CSS has an answer, with a distinction worth knowing: overflow-wrap: anywhere counts the new break points when it works out the minimum width of an element, whereas break-word does not, so inside a flex or grid item only anywhere lets the item shrink (MDN, overflow-wrap). Right-to-left text inserted into a left-to-right sentence can reorder the punctuation around it; MDN recommends the bdi element for text whose direction is unknown, such as names read from a database or typed by a user (MDN, bdi). The empty value leaves a collapsed row or a stray separator. The long list pushes the page far below the fold or makes a dropdown unusable on a phone.
Change one prop at a time. When every fixture differs from the typical one in a single place, a broken layout points at one cause, and the fix does not have to be guessed. Keep every fixture legal under the component's type: mandatory props present, enum props set to a listed value, stated ranges honoured. Data the type forbids exercises the type checker, not the display.
A check that can fail
For the form, take a working sign-in page and break it on purpose, one change at a time: remove the token from the password field, set a code field to number type, add a handler that cancels paste. A review, human or automated, that stays quiet after any of these is not looking at the thing you believed it was looking at. Then run it on a form that is correct, and confirm it stays quiet there too; a safe pattern flagged as a problem is a failure of the check as well.
For the component, render it with the awkward fixtures and measure rather than eyeball. In a browser test, read each element's scroll width and client width and compare them, and check that no element extends past the viewport; an overflow shows up as a number, not as an impression. The check must be capable of failing, so first confirm that it goes red on a deliberately unwrapped long word. The related lesson from our write-up on grid layouts and hydration applies here too: measure the elements themselves, because a page-level figure can hide a clipped child.
When this does not apply
This write-up concerns ordinary HTML forms and components that display text. It does not cover native mobile keyboards, custom widgets that draw their own text field, or payment fields inside a third-party frame, where the vendor controls the markup. Browser and keyboard behaviour differs between operating systems and versions, and the guidance quoted here describes hints, not guarantees: a keyboard may ignore an input mode, and a password manager may ignore a token. Server-side validation, translation length and fonts that lack a glyph were not examined. The list of awkward values is a starting point drawn from documentation and common failures, not a measured ranking of which cause hurts most, and no experiment of ours stands behind it.
Skills for these two checks
Two of our skills cover the steps above. First, the form-input-ux-review skill takes a pasted sign-in, checkout or contact form and reports four kinds of problem: cancelled paste on a password box, a type or input mode mismatched with the data, credential fields with autocomplete off or the wrong token, and a submit button that waits for full validity. Each finding is one line naming the field, the harm and the fix; a clean form gets one fixed reply, and legitimate patterns, like a bounded quantity box, are not reported. The ui-worst-case-data skill takes the prop types of a single component and returns JSON fixtures: an ordinary case first, then one fixture per awkward value the type permits. Function props are listed by name outside the data, and no fixture steps outside the declared types.
Read this post as Markdown: /blog/form-inputs-and-worst-case-ui-data.md · Atom feed.
