Forms and inputs

Labels, input types, validation and submission — everything needed to build forms that people can actually complete.

A form in full

<form action="/subscribe" method="post">
  <label for="email">Email address</label>
  <input id="email" name="email" type="email" required autocomplete="email">

  <label for="plan">Plan</label>
  <select id="plan" name="plan">
    <option value="free">Free</option>
    <option value="pro">Pro</option>
  </select>

  <button type="submit">Subscribe</button>
</form>
  • Every control needs a name — without it nothing is submitted.
  • Label via for matching the control's id, or by wrapping the control inside the label.
  • button type="submit" submits; inside a form a bare button defaults to submit — specify type="button" to prevent accidents.
⚠️
A placeholder is not a label. It disappears the moment someone types, is often low-contrast, and is not reliably announced. Always use a real label.

Input types earn you free behavior

typeWhat it gives you
email/url/telRight mobile keyboard; format validation
numberNumeric keypad, min/max/step (watch for spinner quirks)
date/timeNative picker; value is YYYY-MM-DD
checkbox/radioSelection; radios share one name
fileUpload picker; form needs enctype="multipart/form-data"
passwordMasked entry; pair with autocomplete
searchClear affordance in some browsers
hiddenValue submitted but not shown
<textarea name="bio" rows="4" minlength="10" maxlength="280"></textarea>
<input type="checkbox" id="terms" name="terms" required>
<label for="terms">I accept the terms</label>
<input type="text" name="country" autocomplete="country-name">

Validation: client side is politeness, server side is security

HTML validation attributes (required, minlength, pattern, min/max) improve UX by catching mistakes instantly. They are a convenience only — an attacker can remove them in DevTools or post directly to your endpoint.

⚠️
Always re-validate every value on the server. Client-side validation is UX; server-side validation is your actual security boundary.
  • autocomplete tokens (e.g. email, postal-code, cc-number) let browsers fill forms correctly and quickly.
  • Group related controls with fieldset + legend — essential for radio groups.
  • novalidate on the form disables native validation bubbles if you need fully custom messaging.

FAQ

Why is my submit also reloading the page?
Default form submission navigates. Either handle submit in JavaScript with event.preventDefault(), or let the POST go to your server normally.
GET or POST?
GET for read-only queries (idempotent, bookmarkable, appears in the URL). POST for anything that changes state or carries sensitive data.

Semantic layout

Last refreshed 2026-09-17.