input types

Every HTML Input Type — Live Demos

5 sections · 22 types

type="number" is often the wrong choice — here's why

Try entering a credit card number in both fields. Left uses type="number". Right uses type="text" inputmode="numeric". Notice what breaks on the left.

❌ type="number" for card number

  • Scroll wheel changes the value
  • Leading zeros stripped (0042 → 42)
  • Shows browser spinners ▲▼
  • Spec: "not for data that only consists of numbers but isn't a number"

✅ type="text" inputmode="numeric"

  • No scroll-wheel change
  • Preserves leading zeros
  • No spinners
  • Numeric keyboard on mobile
--:--:--Type in either field — notice the behavior difference

inputmode decision matrix — mobile keyboard guide

Data typeBest typeinputmodeWhy
Quantity / countnumberSpinner makes sense, no leading zeros
Credit cardtextnumericPreserves spaces, no spinners
ZIP / postal codetextnumericKeeps leading zeros (e.g. 02134)
OTP / PINtextnumericShort code, no leading-zero loss
Price / decimaltextdecimalGets decimal key on mobile
Phone numbertelPhone keypad with *, # keys
EmailemailGets @ and .com keys on mobile
SearchsearchSubmit key labeled "Search" on mobile
Website URLurlGets / and .com keys on mobile

Text-family inputs — all variants with inputmode

Interact with each field. The log shows the current value, type, and what keyboard would appear on mobile.

Standard keyboard
Email keyboard · @ and .com keys
URL keyboard · / and .com keys
Phone keypad · *, # keys
Search keyboard · Enter = "Search" Has native × clear button · role="searchbox"
Standard keyboard · value masked
Numeric pad · no spinners · keeps zeros
Decimal keyboard · keeps formatting
--:--:--Interact with any field — see type, inputmode, and value logged

type="number" — when it's actually correct

Use type="number" only when the value is a true mathematical quantity where incrementing makes sense.

min=1 max=99 step=1
min=1 max=5 step=0.5
min=0 step=0.01
--:--:--Try the spinners and scroll wheel on the number inputs

type="range" with the <output> element — the semantic way

Most tutorials use a <span> to show the range value. The correct semantic element is <output> — it has implicit role="status" for screen readers and connects to the input via for.

50
21°C
50
<!-- Semantic range + output --> <input type="range" id="vol" min="0" max="100" value="50" oninput="this.nextElementSibling.value = this.value"> <output for="vol">50</output> <!-- output has role="status" — SR announces changes -->
--:--:--Drag any slider — output element updates in real time

Linked date inputs — check-in / checkout pattern

Select a check-in date. The checkout input enables with its minimum set to the next day. Change check-in and checkout updates accordingly.

Select a check-in date to enable checkout
--:--:--Select check-in — checkout enables with min = next day

All date/time types — interactive

Value format: YYYY-MM-DD
30-min intervals · 9am–5pm
No timezone — local time only
Format: YYYY-MM · billing cycles, CC expiry
Format: YYYY-Www · sprint planning
Captured via Intl.DateTimeFormat
--:--:--Interact with any date/time input to see its raw value format

type="file" — instant image preview with URL.createObjectURL()

Select an image. Preview appears instantly via URL.createObjectURL() — no FileReader, no base64, one line of code.

PNG, JPG, or WebP · Max 2MB
// One-line instant preview const url = URL.createObjectURL(file); img.src = url; // Revoke when loaded to free memory img.onload = () => URL.revokeObjectURL(url);
--:--:--Select an image file to see instant preview

type="color" — hex to RGB/HSL conversion

Color input always returns a 6-char hex value. Convert it to RGB or CSS custom properties on the fly.

#c026d3 rgb(192, 38, 211) hsl(294, 69%, 49%)
--:--:--Pick a color — see hex, RGB, and HSL conversions

Other special types

<input type="hidden" name="csrf" value="abc123">
Submitted with form but not displayed
Not visible, but present in form data
indeterminate state = some but not all checked
Read the tutorial