HTML Input Types Table
| Type | Renders as | Field note |
|---|---|---|
type="text" | Single-line free text | The universal fallback - unknown types degrade to text, so adopting new types is safe |
type="email" | Text + @ keyboard on mobile | Browser validation is a UX hint, not security - still check server-side |
type="password" | Obscured text | Pair with autocomplete=current-password or new-password - no built-in strength meter |
type="number" | Spinner input | Submits a STRING of digits - step/min/max clamp but JS still parses floats |
type="date" | Native calendar picker | Kills datepicker libraries for simple cases - min/max/step constrain the wheel |
type="checkbox" / radio | Toggle / single-choice group | Radios group by NAME attribute - wrap in fieldset+legend for the accessible label |
type="range" | Slider | Shows no value - pair with an output element bound via oninput |
type="color" | Native color picker | Always returns lowercase #rrggbb - no alpha channel, format fixed |
type="file" | Picker + drag-drop target | accept=.pdf,image/* filters the dialog; multiple for batches; File API reads them |
type="hidden" | Nothing rendered | Still submitted with the form - state transport, NOT a security boundary |
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
- 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.
- Constrain native pickers with attributes: min, max and step on date and number types bound the input before any JavaScript runs.
- 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.