When you first met forms, the <input> element looked like a single tool. But it’s really more like a Swiss Army knife — one tag that becomes a completely different field depending on one attribute: type. Change type="text" to type="email", and the browser starts validating email addresses for you. Change it to type="date", and you get a calendar picker. Change it to type="color", and a color wheel pops open.
Picking the right type is one of the highest-value habits in HTML. The correct type gives you free validation, a better on-screen keyboard on phones, the right native UI, and better accessibility — all without a single line of JavaScript. This article walks through every input type worth knowing, what each one hands you, and when to use it.
If you haven’t yet read the basics of building a form, it’s worth skimming HTML Forms and Inputs first — this article assumes you already know what <form>, <label>, and <input> are.
How the type attribute works
Every <input> defaults to type="text" if you don’t specify one. The type attribute tells the browser what kind of data the field holds, and the browser adapts the field to match:
<input type="text" />
<input type="email" />
<input type="number" />
<input type="date" />
These four lines all produce an <input>, but each behaves differently. The text one accepts anything. The email one checks for an @ before it lets the form submit. The number one shows tiny up/down arrows and rejects letters. The date one opens a calendar. Same element, four experiences — all driven by that one word.
The mobile keyboard changes too
On phones and tablets, the input type quietly changes which on-screen keyboard appears. type="email" shows a keyboard with @ and . ready to go. type="tel" shows a number pad. type="url" adds a .com key. Choosing the right type isn’t just about validation — it’s a real comfort upgrade for the majority of users who are on a phone.
Text-based input types
These all look like a text box, but each one tweaks behavior, validation, or the keyboard.
text — the plain default
The everyday field for names, titles, short free-form answers — anything that doesn’t fit a more specific type:
<label for="name">Full name</label>
<input type="text" id="name" name="name" />
email — validates an address shape
The browser checks the value looks like an email (it has an @ and some text on both sides) before allowing submission:
<label for="email">Email</label>
<input type="email" id="email" name="email" placeholder="john@example.com" />
If John Doe types john@@example and hits submit, the browser blocks it and shows a built-in message — no JavaScript required. Add the multiple attribute and the field will accept a comma-separated list of addresses.
password — hides what’s typed
Characters appear as dots or asterisks so nobody can read the value over the user’s shoulder:
<label for="pw">Password</label>
<input type="password" id="pw" name="password" />
password hides, it does not secure
A password input only hides the text visually. It does nothing to encrypt or protect the value as it travels to your server — that’s the job of HTTPS and your backend. Never assume type="password" makes data safe; it just keeps it off the screen.
search — a search box
Functionally like text, but browsers often style it as a rounded search field and may add a small “clear” (×) button:
<input type="search" name="q" placeholder="Search articles…" />
tel — a phone number
There are too many valid phone formats worldwide for the browser to validate, so tel does not check the value. What it does do is bring up the numeric phone keypad on mobile — a genuinely useful win:
<label for="phone">Phone</label>
<input type="tel" id="phone" name="phone" />
url — a web address
Validates that the value is a proper URL (it expects a scheme like https://):
<input type="url" name="website" placeholder="https://acy-partner.com" />
Number and range inputs
number — a numeric field
Accepts only numbers, shows spinner arrows, and pairs beautifully with min, max, and step:
<label for="qty">Quantity</label>
<input type="number" id="qty" name="qty" min="1" max="10" step="1" value="1" />
min/maxset the allowed range.stepcontrols the increment —step="0.5"allows half-steps,step="any"allows any decimal.
Use tel for things that look like numbers but aren't
type="number" is for actual quantities you’d do math on — age, price, count. It is the wrong choice for credit card numbers, phone numbers, postal codes, or OTP codes, because those can have leading zeros, spaces, or lengths that the number spinner mangles. For those, reach for type="text" (often with inputmode="numeric") or type="tel".
range — a slider
When the exact number matters less than picking a value somewhere on a scale, range gives you a draggable slider:
<label for="volume">Volume</label>
<input type="range" id="volume" name="volume" min="0" max="100" value="50" />
The user drags rather than types. Because the value is invisible on the slider itself, it’s common to show it live with a little JavaScript or an <output> element next to it.
Date and time inputs
These open native pickers, so the user never has to guess your preferred date format.
<label for="dob">Date of birth</label>
<input type="date" id="dob" name="dob" />
<label for="appt">Appointment time</label>
<input type="time" id="appt" name="appt" />
<input type="datetime-local" name="meeting" />
<input type="month" name="billing" />
<input type="week" name="sprint" />
date— a calendar, gives a value like2026-08-07.time— hours and minutes.datetime-local— date and time together, without a timezone.month— a whole month (2026-08).week— a specific week number.
You can constrain dates with min and max just like numbers, for example min="2026-01-01" to block past dates.
The value is always in a fixed format
However the calendar looks to the user — Indonesian, American, or anything else — the value your form actually sends is always the standardized ISO format (YYYY-MM-DD for dates). The browser handles the localized display; you receive a clean, predictable string. That consistency is one of the best reasons to use the native date inputs instead of three separate dropdowns.
Choice inputs: checkbox and radio
These two are special — they don’t hold typed text, they represent a choice, and they lean heavily on the name and value attributes.
checkbox — independent on/off toggles
Each checkbox is its own yes/no switch. Several can be checked at once:
<label><input type="checkbox" name="topics" value="html" /> HTML</label>
<label><input type="checkbox" name="topics" value="css" /> CSS</label>
<label><input type="checkbox" name="topics" value="js" checked /> JavaScript</label>
The checked attribute makes a box ticked by default. Each box submits its value only when it’s checked.
radio — pick exactly one from a group
Radio buttons that share the same name form a group, and only one in that group can be selected at a time:
<p>Choose a plan:</p>
<label><input type="radio" name="plan" value="free" checked /> Free</label>
<label><input type="radio" name="plan" value="pro" /> Pro</label>
<label><input type="radio" name="plan" value="team" /> Team</label>
Radio buttons must share a name
The grouping magic of radio buttons comes entirely from the name attribute. If you forget to give them the same name, every radio becomes its own group and the user can select all of them at once — which defeats the whole point. Same name = one choice; different name = independent buttons.
Specialized inputs
A few more types cover specific jobs.
color — a color picker
Opens the operating system’s color wheel and returns a hex value like #00b8e6:
<label for="brand">Brand color</label>
<input type="color" id="brand" name="brand" value="#00b8e6" />
file — upload a file
Lets the user pick a file (or several) from their device. The accept attribute hints at allowed types, and multiple lets them choose more than one:
<label for="avatar">Profile photo</label>
<input type="file" id="avatar" name="avatar" accept="image/*" />
hidden — data the user doesn’t see
A field that’s invisible on the page but still submitted with the form. Handy for sending along an ID or token without showing it:
<input type="hidden" name="form_id" value="contact-2026" />
submit, reset, and button
Inputs can also be buttons, though the standalone <button> element is usually nicer:
<input type="submit" value="Send" />
<input type="reset" value="Clear form" />
submit sends the form, reset clears all fields back to their defaults, and the plain button does nothing until JavaScript wires it up.
Pairing types with validation attributes
Input types get a lot more powerful when you combine them with validation attributes. These work together, hand in hand:
<input type="email" name="email" required />
<input type="number" name="age" min="18" max="120" required />
<input type="text" name="username" minlength="3" maxlength="20" required />
<input type="url" name="site" pattern="https://.*" />
required— the field must be filled before submit.min/max— numeric or date bounds.minlength/maxlength— character limits for text.pattern— a regular expression the value must match.
The type sets the kind of data; these attributes set the rules around it. Together they give you a remarkable amount of validation for free, before any data ever leaves the browser.
Never trust the browser as your only check
Built-in validation is fantastic for guiding honest users, but it is trivial to bypass — anyone can disable JavaScript, edit the HTML, or send a request straight to your server. Client-side validation is a convenience layer, not a security layer. Always validate (and sanitize) every value again on the backend. The browser keeps users on the happy path; your server keeps your data safe.
How to choose the right type
When you add a field, ask one question: what kind of data is this, really? Then pick the type that matches.
- A name or free text →
text - An email address →
email - A secret →
password - A phone number →
tel - A website →
url - A real quantity you’d calculate with →
number - A value on a scale →
range - A date or time →
date/time/datetime-local - One choice from a few →
radio - Several independent toggles →
checkbox - A color →
color - A file upload →
file
Reaching for the specific type instead of defaulting to text is what separates a form that works from a form that’s a genuine pleasure to fill in — especially on a phone, where the right keyboard alone saves people real effort.
Wrapping up
The type attribute is the single most consequential decision you make on an <input>. Here’s what to carry forward:
- One
<input>element becomes many different fields purely through itstype. - The right type gives you free validation, the right mobile keyboard, and the correct native UI — no JavaScript needed.
- Text-family types (
text,email,password,search,tel,url) tune validation and the keyboard. numberis for real quantities; usetextortelfor codes and IDs that aren’t math.- Date/time types return a clean, standardized value while showing a friendly localized picker.
radioandcheckboxrepresent choices and depend onnameandvalueto work correctly.- Specialized types (
color,file,hidden,submit) cover the rest. - Combine types with
required,min/max,pattern, and friends — but always re-validate on the server.
Once you’re comfortable choosing types, the natural next step is shaping how a long form is organized — grouping fields, adding helper text, and laying everything out cleanly. That’s where structure and styling take over from the raw building blocks you’ve just mastered.