Field type selection

Pick the field type based on what the user is entering, not what is easiest to build. The table below maps answer types to the right component.

Answer typeComponentNotes
Free text, shortInputName, email, phone, URL. Set type for keyboard and autocomplete.
Free text, longTextareaBio, notes, description. Show character limit if one exists.
One of 2–5 optionsRadioAlways show all options. Never pre-select unless a default is genuinely safe.
One of 6+ optionsSelectUse a placeholder. Avoid when fewer than 5 items could be Radios.
True / false opt-inCheckboxFor terms, newsletter opt-ins. Unchecked by default unless explicitly pre-agreed.
Many of N optionsCheckbox groupLabel the group with a FormGroup. Show 5 options max before adding a scroll or "show more".
On/off preferenceSwitchFor settings that take effect immediately. Not for form submissions where nothing happens until Submit.

Layout

Single-column is almost always right. Two-column works only when two fields are semantically paired and visually equal in length (first name / last name, start date / end date). Never use two columns just to fit more above the fold.

RuleGuidance
Max widthCap form width at 480px for single-column. Wider fields feel formless and harder to scan.
Field orderLeast friction first. Personal details before payment, basics before advanced options.
GroupingCluster related fields with a section heading or visual separator. Avoid random ordering.
Two-column exceptionOnly for pairs where both fields have similar input length. First name / last name. Start / end date.
LabelsAlways above the field. Never placeholder-only — placeholder disappears on input.

Required fields

Always state the convention at the top of the form before the first field. Mark required fields with * in red next to the label. If nearly every field is required, it is cleaner to mark the one or two optional fields as "optional" instead.

The required prop on Input, Textarea, Select, Checkbox, and FormGroup adds the visual * automatically and sets the native required attribute for browser validation.

<p className="form-note">Fields marked with * are required.</p>

<FormGroup label="Email" required>
  <Input id="email" type="email" />
</FormGroup>

<FormGroup label="Company">
  <Input id="company" placeholder="Optional" />
</FormGroup>

Validation timing

When errors appear matters as much as what they say. Showing errors before the user has finished typing creates anxiety. Showing them only on submit delays feedback on recoverable mistakes.

MomentBehavior
Before interactionShow labels and neutral hints only. No errors, no success states.
While typingCharacter count for constrained fields only (e.g. Twitter-style). No inline errors yet.
On blurShow field-specific format errors. Not required-field errors — the user may not be done with the form yet.
On submitShow all blocking errors. Move keyboard focus to the first invalid field. Summarize at top if more than 3 errors.
After correctionClear the error immediately when the condition is resolved. Don't wait for submit.

Error copy

Error messages should say what is wrong and how to fix it. Not what the system rejected.

AvoidPrefer
"Invalid email address""Enter a valid email like name@example.com"
"This field is required""Enter your first name"
"Password does not meet requirements""Add at least one number and one special character"
"Error occurred""Could not save changes. Check your connection and try again."

Password fields

Show requirements from the moment the field is focused, not after submit. Checking off requirements as the user types reduces anxiety and removes guesswork.

The standard requirement set is: 12 characters minimum, 1 uppercase letter, 1 number, 1 special character. The eye icon toggles password visibility and is built into the Input component when type="password".

<Input
  id="password"
  type="password"
  label="Password"
  required
  hint="12+ characters, 1 uppercase, 1 number, 1 special character"
/>

Submit placement

The primary action goes at the bottom-left of the form, aligned with the input fields. Cancel or secondary actions sit next to it, never above. Right-aligned submit buttons feel disconnected from the content the user just filled in.

ContextButton placement
Standalone form pageBottom-left. Primary action first, destructive or cancel second.
ModalBottom-right of the footer. Cancel left, primary right.
Inline editImmediately below or beside the field that triggered the edit mode.
Multi-stepBack left, Next/Submit right. Do not hide the back action.

Do and don't

Do

Keep scope focused so users can complete the flow without context switches.

Show errors close to fields and clear them as soon as the condition is resolved.

Keep Back and Submit placement consistent across steps.

Don't

Do not hide field meaning once users start typing.

Avoid forcing users through multiple failed submissions to discover issues.

Do not rely on color alone to communicate required or invalid states.