HTML input elements are the backbone of web forms. With over 20 input types and dozens of attributes, understanding how to use them correctly is critical for building accessible, user-friendly, and mobile-optimized forms. This complete HTML input types and attributes guide covers every input type, validation attribute, accessibility best practice, and mobile optimization technique you need.
Build HTML tables for your forms with our HTML Table Generator β
1. Text Input Types
Text-based inputs are the most common form elements. HTML5 introduced several specialized text types that provide built-in validation and trigger appropriate mobile keyboards.
Basic Text Input
The text type is the default and most versatile input. It accepts any string value and is suitable for names, addresses, and general free-form text.
<!-- Basic text input -->
<label for="username">Username:</label>
<input type="text" id="username" name="username"
placeholder="Enter your username"
maxlength="30" required>
<!-- With pattern validation -->
<label for="zipcode">ZIP Code:</label>
<input type="text" id="zipcode" name="zipcode"
pattern="[0-9]{5}" title="5-digit ZIP code"
placeholder="12345">Password Input
The password type masks user input with dots or asterisks. Browsers may offer to save passwords and autofill them on subsequent visits.
<label for="password">Password:</label>
<input type="password" id="password" name="password"
minlength="8" maxlength="128" required
autocomplete="new-password"
aria-describedby="pwd-help">
<small id="pwd-help">Minimum 8 characters</small>Email Input
The email type provides built-in email format validation. On mobile devices, it triggers a keyboard with the @ symbol readily accessible.
<label for="email">Email:</label>
<input type="email" id="email" name="email"
placeholder="user@example.com" required
autocomplete="email">
<!-- Allow multiple emails (comma-separated) -->
<input type="email" id="emails" name="emails" multiple>Telephone Input
The tel type does not enforce any specific format (phone number formats vary by country), but it triggers the numeric phone keypad on mobile devices.
<label for="phone">Phone:</label>
<input type="tel" id="phone" name="phone"
pattern="[+]?[0-9]{1,4}[\s-]?[0-9]{6,14}"
placeholder="+1 555-123-4567"
autocomplete="tel">URL Input
The url type validates that the input contains a valid URL format. On mobile, it typically shows a keyboard with / and .com keys.
<label for="website">Website:</label>
<input type="url" id="website" name="website"
placeholder="https://example.com"
autocomplete="url">Search Input
The search type behaves like a text input but may be styled differently by the browser (e.g., with a clear button) and pairs with the search ARIA role.
<label for="search">Search:</label>
<input type="search" id="search" name="q"
placeholder="Search articles..."
aria-label="Search articles">2. Number & Range Inputs
Numeric inputs restrict user input to numbers and provide spinner controls. The range type offers a slider interface for selecting values within a defined range.
Number Input
The number type shows spinner arrows for incrementing/decrementing. Use min, max, and step attributes to control the allowed range and increment.
<!-- Basic number input -->
<label for="quantity">Quantity:</label>
<input type="number" id="quantity" name="quantity"
min="1" max="100" step="1" value="1">
<!-- Decimal number (e.g., price) -->
<label for="price">Price:</label>
<input type="number" id="price" name="price"
min="0" max="99999.99" step="0.01"
placeholder="0.00">Range Input (Slider)
The range type renders a slider control. Unlike number, it does not show the exact value by default β you need JavaScript or an <output> element to display it.
<!-- Range slider with output display -->
<label for="volume">Volume:</label>
<input type="range" id="volume" name="volume"
min="0" max="100" step="5" value="50"
oninput="this.nextElementSibling.value = this.value">
<output>50</output>
<!-- Range with list of tick marks -->
<input type="range" min="0" max="100" step="25" list="marks">
<datalist id="marks">
<option value="0" label="0%"></option>
<option value="25" label="25%"></option>
<option value="50" label="50%"></option>
<option value="75" label="75%"></option>
<option value="100" label="100%"></option>
</datalist>3. Date & Time Inputs
HTML5 date and time inputs provide native date pickers without requiring a JavaScript library. Browser support is now excellent across modern browsers.
Date Input
The date type presents a date picker UI. The value is always formatted as YYYY-MM-DD regardless of the displayed format.
<label for="birthday">Birthday:</label>
<input type="date" id="birthday" name="birthday"
min="1900-01-01" max="2025-12-31"
value="2000-01-15">Time Input
The time type allows selecting a time of day. The value is in 24-hour HH:MM format, though the display may show AM/PM based on locale.
<label for="meeting">Meeting Time:</label>
<input type="time" id="meeting" name="meeting"
min="09:00" max="18:00" step="900"
value="14:30">
<!-- step="900" = 15-minute increments (900 seconds) -->DateTime-Local Input
The datetime-local type combines date and time selection into a single input. Note: The deprecated datetime type should no longer be used.
<label for="appointment">Appointment:</label>
<input type="datetime-local" id="appointment"
name="appointment"
min="2025-01-01T08:00"
max="2025-12-31T18:00">Month Input
The month type allows selecting a year and month combination. Useful for credit card expiration dates or monthly reports.
<label for="card-exp">Card Expiry:</label>
<input type="month" id="card-exp" name="card-exp"
min="2025-01" max="2035-12">Week Input
The week type allows selecting a specific week of a year. The value format is YYYY-Wnn (e.g., 2025-W03).
<label for="week">Select Week:</label>
<input type="week" id="week" name="week"
min="2025-W01" max="2025-W52">4. Selection Inputs
Selection inputs let users choose from predefined options. These include checkboxes, radio buttons, dropdown selects, and the modern datalist element.
Checkbox
Checkboxes allow users to select zero or more options from a set. Each checkbox operates independently. Use the checked attribute for default selection.
<fieldset>
<legend>Interests:</legend>
<label>
<input type="checkbox" name="interests" value="coding" checked>
Coding
</label>
<label>
<input type="checkbox" name="interests" value="design">
Design
</label>
<label>
<input type="checkbox" name="interests" value="devops">
DevOps
</label>
</fieldset>
<!-- Single checkbox for boolean (e.g., terms) -->
<label>
<input type="checkbox" name="terms" required>
I agree to the Terms of Service
</label>Radio Buttons
Radio buttons let users select exactly one option from a group. All radio buttons in a group must share the same name attribute.
<fieldset>
<legend>Payment Method:</legend>
<label>
<input type="radio" name="payment" value="credit" checked>
Credit Card
</label>
<label>
<input type="radio" name="payment" value="paypal">
PayPal
</label>
<label>
<input type="radio" name="payment" value="bank">
Bank Transfer
</label>
</fieldset>Select Dropdown
The <select> element creates a dropdown menu. While not an <input>, it is essential for form selection. Use multiple for multi-select.
<!-- Single select -->
<label for="country">Country:</label>
<select id="country" name="country" required>
<option value="">-- Select --</option>
<optgroup label="North America">
<option value="us">United States</option>
<option value="ca">Canada</option>
</optgroup>
<optgroup label="Europe">
<option value="uk">United Kingdom</option>
<option value="de">Germany</option>
</optgroup>
</select>
<!-- Multi-select -->
<label for="skills">Skills (hold Ctrl to select multiple):</label>
<select id="skills" name="skills" multiple size="5">
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="js">JavaScript</option>
<option value="ts">TypeScript</option>
<option value="react">React</option>
</select>Datalist (Autocomplete)
The <datalist> element provides autocomplete suggestions for an <input>. Users can type freely or choose from the suggestions.
<label for="browser">Browser:</label>
<input type="text" id="browser" name="browser"
list="browsers" placeholder="Start typing...">
<datalist id="browsers">
<option value="Chrome">
<option value="Firefox">
<option value="Safari">
<option value="Edge">
<option value="Opera">
</datalist>5. File & Media Inputs
File inputs allow users to upload files from their device. The hidden and image types serve special purposes in form handling.
File Upload
The file type opens a file picker dialog. Use accept to restrict file types and multiple to allow multi-file selection.
<!-- Single file upload -->
<label for="avatar">Upload Avatar:</label>
<input type="file" id="avatar" name="avatar"
accept="image/png, image/jpeg, image/webp">
<!-- Multiple files -->
<label for="documents">Upload Documents:</label>
<input type="file" id="documents" name="documents"
accept=".pdf,.doc,.docx" multiple>
<!-- Any image -->
<input type="file" accept="image/*" capture="environment">
<!-- capture="environment" opens rear camera on mobile -->
<!-- capture="user" opens front camera -->Image Submit Button
The image type creates a graphical submit button. When clicked, the form submits along with the x/y coordinates of the click position.
<!-- Image as submit button -->
<input type="image" src="/img/submit-btn.png"
alt="Submit Form" width="100" height="40">
<!-- Submits: x=123&y=45 (click coordinates) -->Hidden Input
The hidden type stores data that is submitted with the form but not visible to the user. Commonly used for CSRF tokens, IDs, and tracking data.
<!-- CSRF token -->
<input type="hidden" name="_csrf" value="abc123token">
<!-- Record ID for update forms -->
<input type="hidden" name="userId" value="42">
<!-- Tracking / analytics -->
<input type="hidden" name="referrer" value="google">6. Button Types
Understanding the differences between button types is crucial for correct form behavior. Using the wrong type can cause unexpected form submissions.
Submit Button
The submit type triggers form submission. This is the default behavior of <button> elements inside a form.
<!-- Using <input> -->
<input type="submit" value="Submit Form">
<!-- Using <button> (preferred - allows HTML content) -->
<button type="submit">
Submit Form
</button>
<!-- Submit to a different URL -->
<button type="submit" formaction="/api/draft" formmethod="post">
Save as Draft
</button>Reset Button
The reset type restores all form controls to their initial values. Use sparingly β users rarely want this functionality and may click it by accident.
<input type="reset" value="Reset Form">
<!-- or -->
<button type="reset">Clear All Fields</button>Generic Button
The button type has no default behavior. Use it for JavaScript-driven actions that should not submit or reset the form.
<!-- IMPORTANT: Always set type="button" for non-submit buttons -->
<button type="button" onclick="togglePreview()">
Toggle Preview
</button>
<!-- Without type="button", this defaults to submit inside a form! -->
<button type="button" id="add-row">Add Row</button>7. Validation Attributes
HTML5 provides powerful built-in validation that reduces the need for JavaScript. These attributes work with the Constraint Validation API to provide immediate feedback.
required
The required attribute prevents form submission if the field is empty. It works with text, email, password, file, checkbox, radio, select, and more.
<input type="text" name="fullname" required>
<input type="email" name="email" required>
<input type="checkbox" name="agree" required>
<!-- Style required fields with CSS -->
<style>
input:required { border-left: 3px solid #e74c3c; }
input:valid { border-left: 3px solid #2ecc71; }
</style>pattern
The pattern attribute specifies a regular expression that the input value must match. Always provide a title attribute explaining the expected format.
<!-- US phone number -->
<input type="tel" name="phone"
pattern="\(\d{3}\) \d{3}-\d{4}"
title="Format: (123) 456-7890">
<!-- Username: letters, numbers, underscores, 3-16 chars -->
<input type="text" name="username"
pattern="[a-zA-Z0-9_]{3,16}"
title="3-16 characters: letters, numbers, underscores">
<!-- Strong password pattern -->
<input type="password" name="password"
pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}"
title="At least 8 chars with uppercase, lowercase, and number">minlength & maxlength
These attributes restrict the number of characters a user can enter. maxlength physically prevents typing beyond the limit; minlength triggers validation on submission.
<!-- Bio: 10 to 500 characters -->
<textarea name="bio" minlength="10" maxlength="500"
rows="4" required></textarea>
<!-- Tweet-like character limit -->
<input type="text" name="status" maxlength="280"
placeholder="What's happening?">min & max
The min and max attributes set boundaries for numeric and date inputs. Values outside this range will fail validation.
<!-- Age: 18 to 120 -->
<input type="number" name="age" min="18" max="120">
<!-- Date range -->
<input type="date" name="start"
min="2025-01-01" max="2025-12-31">
<!-- Price: $0.01 to $9999.99 -->
<input type="number" name="price"
min="0.01" max="9999.99" step="0.01">8. Styling & UX Attributes
These attributes enhance user experience by providing hints, controlling autofill behavior, and guiding focus.
placeholder
The placeholder attribute shows hint text inside the input. It disappears when the user starts typing. Never use placeholder as a substitute for a label β it is not accessible and disappears on input.
<!-- Good: Label + placeholder as hint -->
<label for="email">Email Address</label>
<input type="email" id="email" placeholder="user@example.com">
<!-- Bad: Placeholder as only label (not accessible!) -->
<input type="email" placeholder="Email Address">
<!-- Style placeholder text with CSS -->
<style>
::placeholder {
color: #999;
font-style: italic;
}
</style>autofocus
The autofocus attribute automatically focuses the input when the page loads. Only one element per page should have this attribute. Use sparingly as it can be disorienting for screen reader users.
<!-- Focus the search box on page load -->
<input type="search" name="q" autofocus
placeholder="Search...">autocomplete
The autocomplete attribute hints to the browser what kind of data is expected, enabling smart autofill. Values include name, email, tel, address-line1, cc-number, and many more.
<!-- Full autocomplete for address form -->
<input type="text" name="name" autocomplete="name">
<input type="email" name="email" autocomplete="email">
<input type="tel" name="phone" autocomplete="tel">
<input type="text" name="address" autocomplete="address-line1">
<input type="text" name="city" autocomplete="address-level2">
<input type="text" name="state" autocomplete="address-level1">
<input type="text" name="zip" autocomplete="postal-code">
<input type="text" name="country" autocomplete="country-name">
<!-- Credit card fields -->
<input type="text" name="cc-name" autocomplete="cc-name">
<input type="text" name="cc-number" autocomplete="cc-number"
inputmode="numeric">
<input type="text" name="cc-exp" autocomplete="cc-exp">
<input type="text" name="cc-csc" autocomplete="cc-csc"
inputmode="numeric">
<!-- Disable autocomplete for sensitive fields -->
<input type="text" name="otp" autocomplete="off">inputmode
The inputmode attribute controls which virtual keyboard is displayed on mobile devices without changing the input type or validation behavior.
<!-- inputmode values and their keyboards -->
<input inputmode="text"> <!-- Default keyboard -->
<input inputmode="numeric"> <!-- 0-9 only -->
<input inputmode="decimal"> <!-- 0-9 + decimal point -->
<input inputmode="tel"> <!-- Telephone keypad -->
<input inputmode="email"> <!-- @ and . visible -->
<input inputmode="url"> <!-- / and .com visible -->
<input inputmode="search"> <!-- Search/Go button -->
<input inputmode="none"> <!-- No keyboard -->9. Accessibility Best Practices
Accessible forms ensure all users, including those using screen readers and assistive technology, can interact with your inputs. Accessibility is not optional β it is a legal requirement in many jurisdictions.
Labels
Every input must have an associated <label>. Use the for attribute matching the input's id, or wrap the input inside the label element.
<!-- Method 1: Explicit label with for/id -->
<label for="fname">First Name:</label>
<input type="text" id="fname" name="fname">
<!-- Method 2: Implicit label (wrapping) -->
<label>
Last Name:
<input type="text" name="lname">
</label>
<!-- WRONG: No label association -->
<span>Email:</span>
<input type="email" name="email">
<!-- Screen readers cannot identify what this field is for -->ARIA Attributes
ARIA attributes provide additional context to assistive technologies. Use aria-describedby for help text, aria-invalid for error states, and aria-required as a supplement to the native required attribute.
<!-- Help text with aria-describedby -->
<label for="pwd">Password:</label>
<input type="password" id="pwd" name="pwd"
aria-describedby="pwd-requirements" required>
<div id="pwd-requirements">
Must contain at least 8 characters, one uppercase,
one lowercase, and one number.
</div>
<!-- Error state with aria-invalid -->
<label for="email">Email:</label>
<input type="email" id="email" name="email"
aria-invalid="true"
aria-describedby="email-error">
<div id="email-error" role="alert">
Please enter a valid email address.
</div>
<!-- aria-required for assistive tech -->
<input type="text" name="company"
aria-required="true" required>Fieldset & Legend
Group related inputs with <fieldset> and provide a group label with <legend>. This is especially important for radio button and checkbox groups.
<fieldset>
<legend>Shipping Address</legend>
<label for="street">Street:</label>
<input type="text" id="street" name="street">
<label for="city">City:</label>
<input type="text" id="city" name="city">
</fieldset>
<fieldset>
<legend>Preferred Contact Method</legend>
<label>
<input type="radio" name="contact" value="email"> Email
</label>
<label>
<input type="radio" name="contact" value="phone"> Phone
</label>
<label>
<input type="radio" name="contact" value="sms"> SMS
</label>
</fieldset>Error Messages
Display error messages near the input they relate to. Use aria-describedby to associate the error with the input, and aria-live="polite" to announce errors to screen readers.
<!-- Accessible error pattern -->
<label for="age">Age:</label>
<input type="number" id="age" name="age"
min="18" max="120" required
aria-invalid="true"
aria-describedby="age-error">
<div id="age-error" role="alert" aria-live="polite"
style="color: red;">
Age must be between 18 and 120.
</div>
<!-- JavaScript for custom validation messages -->
<script>
const ageInput = document.getElementById('age');
ageInput.addEventListener('invalid', (e) => {
if (ageInput.validity.rangeUnderflow) {
ageInput.setCustomValidity('You must be at least 18.');
} else if (ageInput.validity.rangeOverflow) {
ageInput.setCustomValidity('Please enter a realistic age.');
}
});
ageInput.addEventListener('input', () => {
ageInput.setCustomValidity('');
});
</script>10. Mobile Keyboard Optimization
The inputmode attribute gives you fine-grained control over mobile virtual keyboards without changing the input type. This is particularly useful when you need a specific keyboard but want to maintain type="text" for custom validation.
Numeric Keyboard
Use inputmode="numeric" for fields that expect numbers but do not need type="number" behavior (like PIN codes, ZIP codes, or credit card numbers).
<!-- PIN code (numeric keyboard, no spinners) -->
<label for="pin">PIN Code:</label>
<input type="text" id="pin" name="pin"
inputmode="numeric" pattern="[0-9]{4,6}"
maxlength="6" autocomplete="one-time-code">
<!-- ZIP code -->
<input type="text" name="zip"
inputmode="numeric" pattern="[0-9]{5}"
autocomplete="postal-code">Email Keyboard
Use inputmode="email" to show an email-optimized keyboard with @ and . keys prominently displayed.
<input type="email" inputmode="email"
autocomplete="email">Telephone Keyboard
Use inputmode="tel" to display the full telephone keypad, ideal for phone number entry.
<input type="tel" inputmode="tel"
autocomplete="tel">URL Keyboard
Use inputmode="url" to display a keyboard with /, ., and .com keys for URL entry.
<input type="url" inputmode="url"
autocomplete="url">Decimal Keyboard
Use inputmode="decimal" for numeric fields that may include a decimal point, like prices or measurements.
<!-- Price field with decimal keyboard -->
<label for="amount">Amount ($):</label>
<input type="text" id="amount" name="amount"
inputmode="decimal" pattern="[0-9]*\.?[0-9]+"
placeholder="0.00">11. Form Submission & FormData API
Modern JavaScript provides the FormData API for programmatic form handling. Combined with the fetch API, you can submit forms without page reloads.
Basic FormData Usage
The FormData constructor accepts a form element and automatically collects all named input values.
const form = document.querySelector('#myForm');
const formData = new FormData(form);
// Access individual values
const email = formData.get('email'); // string | null
const files = formData.getAll('photos'); // File[]
// Iterate over all entries
for (const [key, value] of formData.entries()) {
console.log(key, value);
}
// Append extra data
formData.append('timestamp', Date.now().toString());
// Convert to plain object
const data = Object.fromEntries(formData.entries());
// Convert to URL-encoded string
const params = new URLSearchParams(formData).toString();
// "name=John&email=john%40example.com"Fetch API with Forms
Use fetch() to submit form data asynchronously. The browser automatically sets the correct Content-Type header when you pass a FormData object.
// Submit as multipart/form-data (for file uploads)
const form = document.querySelector('#uploadForm');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(form);
const response = await fetch('/api/upload', {
method: 'POST',
body: formData,
// Do NOT set Content-Type header manually!
// The browser sets it with the correct boundary
});
const result = await response.json();
console.log(result);
});
// Submit as JSON
form.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(form);
const data = Object.fromEntries(formData.entries());
const response = await fetch('/api/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
});Encoding Types (enctype)
The enctype attribute on <form> controls how form data is encoded before sending. The three options are:
application/x-www-form-urlencodedβ Default. Key-value pairs separated by&. Suitable for most text-only forms.multipart/form-dataβ Required for file uploads. Each field is sent as a separate part with boundary markers.text/plainβ Sends data as plain text. Rarely used; not recommended for production.
<!-- Default: URL-encoded -->
<form method="post" action="/api/contact">
...
</form>
<!-- File upload: Must use multipart -->
<form method="post" action="/api/upload"
enctype="multipart/form-data">
<input type="file" name="document">
<button type="submit">Upload</button>
</form>12. Input Types Comparison Table
The following table summarizes all HTML input types, their primary use cases, mobile keyboard behavior, and browser support status.
| Type | Use Case | Mobile Keyboard | Built-in Validation | Browser Support |
|---|---|---|---|---|
text | General text | Standard | pattern, minlength, maxlength | All |
password | Passwords | Standard (masked) | pattern, minlength, maxlength | All |
email | Email addresses | @ key visible | Email format | All |
tel | Phone numbers | Phone keypad | None (use pattern) | All |
url | Web addresses | / and .com keys | URL format | All |
search | Search queries | Search button | None | All |
number | Numeric values | Number pad | min, max, step | All |
range | Value in range | N/A (slider) | min, max, step | All |
date | Calendar date | Date picker | min, max | All modern |
time | Time of day | Time picker | min, max, step | All modern |
datetime-local | Date + time | Date-time picker | min, max | All modern |
month | Year + month | Month picker | min, max | Partial (no Firefox) |
week | Year + week | Week picker | min, max | Partial (no Firefox) |
checkbox | Multiple selection | N/A | required | All |
radio | Single selection | N/A | required | All |
file | File upload | File picker | accept, required | All |
hidden | Hidden data | N/A | None | All |
image | Image submit | N/A | None | All |
color | Color picker | Color palette | None | All modern |
submit | Form submit | N/A | Triggers validation | All |
reset | Form reset | N/A | None | All |
button | Custom action | N/A | None | All |
Frequently Asked Questions
What is the difference between type="button" and type="submit"?
type="submit" triggers form submission and validation when clicked. type="button" has no default behavior β it requires JavaScript to perform any action. Inside a <form>, a <button> without an explicit type defaults to submit, which can cause accidental form submissions. Always set type="button" for non-submit buttons.
Should I use type="number" or inputmode="numeric" for credit card fields?
Use type="text" with inputmode="numeric" for credit card numbers. type="number" adds spinner arrows, allows scientific notation (e.g., 1e2), and may strip leading zeros β all undesirable for card numbers. The inputmode attribute gives you the numeric keyboard without these side effects.
How do I make a date input required and set min/max dates?
Add the required attribute along with min and max attributes in YYYY-MM-DD format: <input type="date" required min="2024-01-01" max="2025-12-31">. The browser will prevent submission if the field is empty or the date is outside the allowed range.
What is the best way to handle file upload size limits in HTML?
HTML alone cannot enforce file size limits. The accept attribute restricts file types (e.g., accept=".pdf,.docx" or accept="image/*"), but size validation must be done with JavaScript using input.files[0].size on the change event, or on the server side. Always validate on the server regardless of client-side checks.
How do I style the native HTML validation error messages?
You cannot directly style native browser validation tooltips. However, you can use the :invalid, :valid, :required, and :user-invalid CSS pseudo-classes to style the inputs themselves. For fully custom error messages, use the Constraint Validation API: call input.setCustomValidity("message") and use input.reportValidity(). Alternatively, suppress native popups with novalidate on the form and implement custom validation UI entirely in JavaScript.
Bookmark this page as your reference for HTML input types and attributes. For building HTML-based forms and tables, try our tools below.