< Modern HTML >

< input >

The input element: twenty-two types, one tag

A family of native form controls, each with behavior the browser has refined over decades. The type attribute is not cosmetic. Changing type="text" to type="email" is not a label change. It swaps the keyboard on mobile, enables built-in validation, changes the autofill category, and tells assistive technology the semantic kind of the field. The input element is the clearest example of how much the browser already does that does not need to be rebuilt.

Because the input element covers twenty-two types, this page is a map of the territory rather than a full tour. Each type will have its own page in this reference. What follows is what is shared across types, what the type attribute buys, and the surprising capabilities present across many of them.

The type attribute selects a different element, effectively

Each value of type gives the input a different UI, a different validation rule, a different virtual keyboard on mobile, a different autofill category, and a different value format. The twenty-two types fall into a handful of families:

Each will get its own page. What follows are the attributes and behaviors that cut across many of them.

Built-in with native HTML

Across the input family, the browser provides:

Autofill is a specification, not a suggestion

The autocomplete attribute accepts a standardized set of tokens defined in the HTML specification. Values like name, given-name, family-name, email, tel, street-address, postal-code, country, cc-number, cc-exp, cc-csc, and bday are not arbitrary strings. They are a vocabulary the browser's autofill database maps to. Using the correct tokens means a user's saved addresses, credit cards, and contact info populate correctly and automatically.

For one-time codes from SMS: autocomplete="one-time-code". On iOS and Android this surfaces the verification code directly from the SMS keyboard suggestion strip, without the user leaving the app to copy it.

For new passwords: autocomplete="new-password". This signals to password managers to offer generation rather than retrieval.

Getting autocomplete wrong is one of the highest-friction parts of any sign-up or checkout flow, and it is entirely a matter of setting the right attribute values.

The inputmode attribute, separately

inputmode is independent from type and controls only the virtual keyboard on mobile:

A common pairing is type="text" inputmode="numeric" for a value that is numeric in nature but should not use type="number" (which has spinners, scroll-to-change behavior, and locale quirks for decimals). Postal codes, verification codes, and credit-card-number-like fields are usually this combination.

The pattern attribute: regex validation

pattern takes a regular expression that the value must fully match. Combined with title, the browser shows a meaningful error when the pattern fails:

<input type="text"
       pattern="[A-Z]{2}[0-9]{6}"
       title="Two uppercase letters followed by six digits"
       name="reference-code">

The pattern is evaluated against the entire value (as if anchored with ^ and $). It participates in constraint validation, so :invalid and :user-invalid apply when the pattern does not match.

List-based autocomplete with <datalist>

The list attribute points at a <datalist> element, producing a native autocomplete dropdown:

<input type="text" list="countries" name="country">
<datalist id="countries">
  <option value="Canada">
  <option value="Mexico">
  <option value="United States">
</datalist>

This is the native "combobox-lite" pattern. The user can type freely or pick from the list. It works on every input type that accepts a list, which includes most text-family and numeric types. For a true combobox with rich items and filtering, or where the list is long enough to need virtualization, a custom control is warranted. For the common "suggest common values" case, <datalist> is the answer.

File input, quietly capable

<input type="file"> accepts several attributes many authors never touch:

A file input's value is a FileList. Once the user selects files, each File object has a name, size, type, last-modified timestamp, and can be read as text, binary, or a data URL through the FileReader API, or streamed.

Drag-and-drop uploads can be built on top of a file input by styling the input to cover a drop zone and listening for the change event. No third-party upload library is required for the core interaction.

Range: a slider with an API

<input type="range"> is a native slider:

Styling is done through ::-webkit-slider-thumb and ::-webkit-slider-runnable-track, along with the Firefox equivalents. A two-handle range slider is the common case the native element does not cover. For single-handle, the native one is complete.

Paired with a <datalist>, a range input can display tick marks at specified values:

<input type="range" min="0" max="100" step="10" list="ticks">
<datalist id="ticks">
  <option value="0"><option value="25"><option value="50"><option value="75"><option value="100">
</datalist>

Color: a native color picker

<input type="color"> opens the operating system color picker. The value is a seven-character hex string (#rrggbb). For many in-app "theme color" or "highlight" selections, this is sufficient and integrates with the user's OS-level color tools.

Date and time: a native date picker

The date and time types open native pickers: calendar UIs on desktop and native date rollers on mobile. They handle locale formatting automatically. The user sees dates in their own format, the value submitted is always in ISO 8601. This is exactly what a form wants: locale-friendly display, standardized data.

The tradeoff is styling. The native date picker cannot be fully restyled. For most applications (booking, scheduling, filtering by date), the native picker is functional, accessible, and built in.

Checkbox and radio: the semantics

Checkboxes and radios are frequently rebuilt as custom components for styling reasons, and that is where accessibility regressions most often enter a codebase. The native ones have:

Modern CSS, including accent-color, appearance, and ::before/::after on labels, covers most styling needs without replacing the input. When custom visuals are required, the pattern is to visually hide the input (not display: none, which removes it from the tab order) and style a sibling element based on :checked and :focus-visible:

<label class="checkbox">
  <input type="checkbox">
  <span class="check"></span>
  <span class="label">Accept terms</span>
</label>
.checkbox input { position: absolute; opacity: 0; }
.checkbox input:checked + .check { /* checked style */ }
.checkbox input:focus-visible + .check { /* focus style */ }

This keeps the native element in the accessibility tree, keeps keyboard and form participation intact, and still allows full visual design.

Readonly, disabled, and the difference

Use readonly for values the user should see and can copy but not change, like a generated ID or a computed total. Use disabled for controls that are not currently applicable.

Composite patterns across inputs

Already HTML-available

Patterns that HTML handles natively, which are often rebuilt in JavaScript:


Reference:

WHATWG
the-input-element
the inputmode attribute
caniuse.com
mdn-html_elements_input
MDN Docs
Web/HTML/Element/input
autocomplete attribute values