HTML Input Types Table

TypeRenders asField note
type="text"Single-line free textThe universal fallback - unknown types degrade to text, so adopting new types is safe
type="email"Text + @ keyboard on mobileBrowser validation is a UX hint, not security - still check server-side
type="password"Obscured textPair with autocomplete=current-password or new-password - no built-in strength meter
type="number"Spinner inputSubmits a STRING of digits - step/min/max clamp but JS still parses floats
type="date"Native calendar pickerKills datepicker libraries for simple cases - min/max/step constrain the wheel
type="checkbox" / radioToggle / single-choice groupRadios group by NAME attribute - wrap in fieldset+legend for the accessible label
type="range"SliderShows no value - pair with an output element bound via oninput
type="color"Native color pickerAlways returns lowercase #rrggbb - no alpha channel, format fixed
type="file"Picker + drag-drop targetaccept=.pdf,image/* filters the dialog; multiple for batches; File API reads them
type="hidden"Nothing renderedStill submitted with the form - state transport, NOT a security boundary
Reference: the MDN input types reference. Input types are contracts with the browser and the KEYBOARD, not just styling hooks: type=email raises the @ keyboard on phones, type=date summons the native picker, type=number gets the numeric pad - all free with the right attribute. The degradation guarantee makes adoption one-way safe: any unknown type renders as plain text, so no polyfill or support matrix is needed. Bottom line: reach for type=email before writing regex validation, type=date before importing a datepicker, and remember every type still submits a string - client validation is UX, the server re-checks everything. Related tools: HTML attributes table (autocomplete, pattern, required), WAI-ARIA table (labels come first, ARIA second), and semantic elements table (fieldset, label, output).

The type attribute is a contract with the browser, the keyboard and the platform: type=email raises the @ keyboard on phones, type=date summons the native calendar picker, type=file wires up drag-and-drop. One attribute chooses the widget, the validation hint and the mobile input method at once.

Bottom line: reach for type=email before writing regex validation (the browser checks the shape for free), type=date before importing a datepicker library (the native picker is faster, accessible and localized), and remember every type still submits a string - client validation is user experience, and the server re-validates everything.

The honest part: the degradation guarantee is what makes new types safe to adopt. Any type the browser does not know renders and behaves exactly like type=text, so no support matrix, polyfill or feature detection is needed - shipping type=search or type=color can never break an older browser.

How to use

  1. Pick the type for the DATA, not the look: an email field is type=email even if you style it plain - the keyboard and validation follow the data.
  2. Constrain native pickers with attributes: min, max and step on date and number types bound the input before any JavaScript runs.
  3. Group radios by name and wrap them in fieldset with legend - the group label is what screen readers announce, not each checkbox in isolation.

Frequently asked questions

What happens if a browser does not support a newer input type?

It falls back to type=text automatically - that is the contract. An unfamiliar value is not an error; the browser renders a single-line text field and the form submits exactly as before. This is why HTML5 input types shipped safely a decade ago: adopting type=email or type=date cost nothing on old browsers and bought keyboards and validation on new ones. The only visible difference is the enhanced behavior on engines that know the type - there is no broken state to polyfill.

Does type=number fix JavaScript floating point problems?

No - and this traps people constantly. The number input validates the SHAPE of the value (digits, one decimal point, respect for step) but submits a string, and the moment your code does arithmetic, 0.1 + 0.2 still equals 0.30000000000000004. Use the type to constrain what users can type and to get the spinner and numeric keyboard; use real number handling (integer cents, or a decimal library for money) once the value reaches your code. The step attribute also bites: step=any is needed to allow arbitrary decimals.

When is a native date input better than a datepicker library?

For plain date entry, almost always: the native picker is instantly accessible (keyboard, screen reader), localized to the user's language and calendar order, and costs zero kilobytes - a library is a dependency you style, maintain and load on mobile. Reach for a library only when you genuinely need features the native input lacks: multi-date ranges in one control, disabling arbitrary date sets beyond min/max, or time zones displayed alongside. Start native, escalate only on a concrete missing feature.

Is type=hidden a safe place to store sensitive values?

No - hidden only controls RENDERING. The value ships with every form submission, appears in devtools and saved HTML, and can be edited by the user before submit. It is state transport for data the server already knows (a record id, a CSRF token the server will verify), never a secret store. Anything a client must not control should live in server-side sessions; anything that must not be TAMPERED with should be signed or re-verified server-side. The type protects layout, not data.

Related tools