Forms
One focused chapter from the Thorbis interface research. 20 rules. Read the research index for every chapter and focused study.
Forms
- Enter submits. When a text input is focused, Enter submits if it’s the only control. If there are many controls, apply to the last control.Add tech
The error sits on the field. Submit stays enabled. - Textarea behavior. In
<textarea>, ⌘/⌃+Enter submits; Enter inserts a new line. - Labels everywhere. Every control has a
<label>or is associated with one. A placeholder is never a label.Add techThe error sits on the field. Submit stays enabled. - Label activation. Clicking a
<label>focuses the associated control. No dead zone between the text and the input.Add techThe error sits on the field. Submit stays enabled. - Submission rule. Keep submit enabled until the request starts; then disable it, show a spinner, keep the original label, & include an idempotency key.
- Don’t block typing. Even if a field only accepts numbers, allow any input & show validation after. Blocking keystrokes is confusing because the user gets no explanation.Customer phone
Type while it searches. Do not steal the key. - Don’t pre-disable submit. Allow submitting incomplete forms to surface validation. Focus the first invalid field.Add tech
The error sits on the field. Submit stays enabled. - Error placement. Show errors next to their fields with
aria-invalidandaria-describedby. Never a red border alone. The copy tells the user how to fix it.Add techThe error sits on the field. Submit stays enabled. - Error replaces help. Help sits under the field. When the field is invalid, the error takes that seat. One slot. Do not stack help and error. Do not toast a missing name. Shopify’s form cleanliness: the sentence under the well is the only commentary.
- Affixes live in the well. $, %, /hr, and units sit inside the field, as quiet prefixes or suffixes. They are not a second box. They are not a label. The value stays tabular.
- A cluster is space, not a card. Related fields share a heading and a gap. Do not wrap each input in its own sheet. Polaris groups by proximity. We already forbade a line between jobs; the same law applies to a name and a phone.
- Placeholders are examples. A placeholder shows the shape of the answer: Mike Reyes, 114 Oak, $186.00. It is never the label. “Enter name” is a missing label. Shopify’s cleanliness: the field already has a name above it.
- Mark optional, not required. Most fields on a job are required. Stars on every row is noise. Mark the rare skip with the word optional. Polaris does the same for merchants.
- A banner is a page problem. Offline, a failed save for the whole sheet, a permission that blocks the room: those are banners. A missing name stays under Name. Shopify’s banners are page-level. Field errors are not.
- Autocomplete & names. Set
autocomplete& meaningfulnamevalues. Stay compatible with password managers and 2FA autofill. - Spellcheck selectively. Disable for emails, codes, usernames, invoice numbers, and job IDs.
- Correct types & input modes. Use the right
type&inputmode. Money usesinputmode="decimal"ontype="text", not a spinner. - Placeholders signal emptiness. End with an ellipsis, the character in Ellipsis. Set the value to an example:
name@company.com,(706) 555-0142.Customer phoneThe label is the name. The hole is empty. - Unsaved changes. Warn before navigation when data could be lost. Never lose typed input to a re-render.
- Trim before validate. Autocomplete and text expansion add trailing spaces. Trim so a valid value is not rejected.
I built this for the dispatcher at 7 a.m., the tech in a crawlspace, and the owner closing the books. Quiet chrome. Precise work. I’m still learning. These are the notes.
Applied bookmark research
Reviewed 2026-09-06. These examples reinforce the existing owners; they do not introduce another visual style or claim the product behavior is implemented. Read the 26-source review and access limits.
A control keeps its meaning through every state
A button that changes width, a field that loses input, or a dialog that loses focus breaks the task even when the resting design looks precise.
Review the approved primitive as a sequence: resting, focused, activated, pending, resolved, and recovered. Keep the action label and footprint stable, associate errors with their fields, and preserve a visible keyboard path.
Thorbis example. Save estimate remains Save estimate while its state mark changes. A validation error keeps the entered values, explains the repair beside the field, and moves focus only when the interaction calls for it.
Verify. Test Tab, Shift-Tab, Enter, Escape where applicable, paste, invalid input, rapid activation, and a slow response. Repeat at 390px, in both themes, with zoom and reduced motion.
Do not import. No hand-built duplicate primitive, hidden label, disabled browser zoom, or borrowed shadow-only outer edge that violates D-017.
Open the ui skill · Evidence: Web Interface Guidelines; Invisible Details; components.build; Details that make interfaces feel better
Transfer the intent, not the desktop gesture
An interaction that works with a precise pointer or modifier key may be unusable for a tech holding a phone.
Preserve the record and task while adapting the visible action path to the device. Use the existing native owner for target sizing, safe areas, focus, and host behavior; no critical action relies only on hover or a hidden gesture.
Thorbis example. A field photo remains attached to the same job when the tech changes orientation or returns from another app. The visible capture action and retry path remain available without discovering a desktop shortcut.
Verify. Check one-handed use, software keyboard opening, text enlargement, orientation, focus visibility, and reduced motion on the relevant device. Keep permission refusal and return-from-interruption states in the review.
Do not import. No desktop hover contract on a phone, blocked zoom, silent clipboard access, or unverified claim that a web imitation is native behavior.
Open the native skill · Evidence: Web Interface Guidelines; Design Engineer Principles; Devouring Details