|$ curl https://forge-ai.dev/api/markdown?path=docs/html/input-types
$cat docs/html-input-types.md
updated This week·40 min read·published

HTML Input Types

HTMLFormsIntermediateIntermediate
Introduction

HTML5 defines over twenty input types, each optimized for a specific kind of data. The type attribute on the <input> element determines the control's appearance, behavior, and validation rules. Browsers render native controls — date pickers, color pickers, sliders — without requiring any JavaScript.

Choosing the correct input type improves user experience by showing the appropriate mobile keyboard, enabling browser autofill, and providing built-in validation. This section covers every standard input type with practical examples and guidance on when to use each.

TypeHTMLDescriptionMobile Keyboard
text<input type="text">Single-line text input (default)Standard
email<input type="email">Email with built-in format validation@ key, .com shortcut
url<input type="url">URL with built-in format validation.com, / keys
tel<input type="tel">Telephone number (no pattern enforced)Numeric keypad
search<input type="search">Search field with clear buttonSearch key (go)
password<input type="password">Masked text entryStandard
number<input type="number">Numeric with step/range controlsNumeric keypad
checkbox<input type="checkbox">Boolean toggle (multiple selections)
radio<input type="radio">Single-select from group (same name)
date<input type="date">Date picker (YYYY-MM-DD)Native date picker
datetime-local<input type="datetime-local">Date + time picker (no timezone)Native date/time picker
month<input type="month">Month and year pickerNative month picker
week<input type="week">Week and year pickerNative week picker
time<input type="time">Time picker (HH:MM or HH:MM:SS)Native time picker
file<input type="file">File picker (accept, multiple, capture)File browser
range<input type="range">Slider control (min, max, step, value)
color<input type="color">Color picker (hexadecimal value)Native color picker
hidden<input type="hidden">Invisible field for passing data

Live preview showing all the major input types rendered in a grid:

preview
Text Inputs

Text-based input types handle string data with varying validation rules and keyboard presentations. The text type is the default for all <input> elements. Specialized types like email, url, and tel trigger tailored mobile keyboards and provide basic format validation.

TypeValidationAutocompleteUse Case
textNone (free-form)on/offNames, titles, addresses
emailChecks for @ and domainemailEmail signup, contact forms
urlChecks for protocol (http://)urlWebsite fields, link submission
telNone (free-form)telPhone numbers (use pattern for format)
searchNoneoffSearch bars with clear button
passwordNone (characters masked)current-password / new-passwordLogin, password creation
text-inputs.html
HTML
1<!-- Text input with validation attributes -->
2<label for="fullname">Full Name</label>
3<input
4 type="text"
5 id="fullname"
6 name="fullname"
7 placeholder="Jane Doe"
8 minlength="2"
9 maxlength="100"
10 required
11 autocomplete="name"
12/>
13
14<!-- Email with custom pattern -->
15<label for="email">Work Email</label>
16<input
17 type="email"
18 id="email"
19 name="email"
20 placeholder="jane@company.com"
21 pattern="[a-z0-9._%+\-]+@[a-z0-9.\-]+.[a-z]{2,}$"
22 title="Enter a valid email address"
23 required
24 autocomplete="email"
25/>
26
27<!-- Telephone with pattern -->
28<label for="phone">Phone Number</label>
29<input
30 type="tel"
31 id="phone"
32 name="phone"
33 placeholder="+1-555-0123"
34 pattern="[+][0-9]{1,3}[0-9]{3,14}"
35 title="Format: +1-555-0123"
36 autocomplete="tel"
37/>
38
39<!-- URL input -->
40<label for="website">Website</label>
41<input
42 type="url"
43 id="website"
44 name="website"
45 placeholder="https://example.com"
46 autocomplete="url"
47/>
48
49<!-- Search input -->
50<label for="site-search">Search</label>
51<input
52 type="search"
53 id="site-search"
54 name="q"
55 placeholder="Search documentation..."
56 aria-label="Search the documentation"
57/>
58
59<!-- Password with requirements -->
60<label for="password">Create Password</label>
61<input
62 type="password"
63 id="password"
64 name="password"
65 minlength="8"
66 maxlength="128"
67 required
68 autocomplete="new-password"
69/>
70<small>Min 8 characters</small>

info

The pattern attribute uses JavaScript regex syntax. Always provide a matching title attribute that describes the expected format — the title is used in the browser's validation error message. For type="tel", no built-in validation is applied; you must use pattern to enforce format.
Choice Inputs

Checkboxes and radio buttons let users make selections. Checkboxes allow multiple independent choices and are toggled on/off independently. Radio buttons restrict the user to exactly one choice within a group — all radio buttons sharing the same name attribute belong to the same group.

choice-inputs.html
HTML
1<!-- Checkboxes — multiple independent choices -->
2<fieldset>
3 <legend>Subscribe to newsletters (select all that apply)</legend>
4
5 <label>
6 <input type="checkbox" name="newsletters" value="tech" checked />
7 Technology
8 </label>
9 <label>
10 <input type="checkbox" name="newsletters" value="design" />
11 Design
12 </label>
13 <label>
14 <input type="checkbox" name="newsletters" value="business" />
15 Business
16 </label>
17</fieldset>
18
19<!-- Radio buttons — single choice from group -->
20<fieldset>
21 <legend>Preferred Contact Method</legend>
22
23 <label>
24 <input type="radio" name="contact" value="email" checked />
25 Email
26 </label>
27 <label>
28 <input type="radio" name="contact" value="phone" />
29 Phone
30 </label>
31 <label>
32 <input type="radio" name="contact" value="mail" />
33 Postal Mail
34 </label>
35</fieldset>
36
37<!-- Inline checkbox with explicit label association -->
38<input type="checkbox" id="terms" name="terms" required />
39<label for="terms">
40 I agree to the <a href="/terms">Terms of Service</a> and
41 <a href="/privacy">Privacy Policy</a>
42</label>
43
44<!-- Indeterminate checkbox (JavaScript) -->
45<input type="checkbox" id="selectAll" />
46<label for="selectAll">Select All Items</label>
47
48<script>
49 const selectAll = document.getElementById('selectAll');
50 selectAll.indeterminate = true;
51</script>

best practice

Wrap each checkbox or radio in a <label> element for implicit association. This makes the entire label text clickable — a significant usability improvement, especially on mobile. Use <fieldset> and <legend> to group related controls with a shared description.

Live preview of checkboxes and radio buttons with custom styling:

preview
Date & Time Inputs

HTML5 date and time inputs provide native date pickers, time selectors, and combined controls. Browser support is excellent on modern browsers, with each browser rendering its own platform-native picker. The value format for date inputs is always YYYY-MM-DD, regardless of the user's locale.

TypeValue FormatExampleAttributes
dateYYYY-MM-DD2026-07-07min, max, step (days)
datetime-localYYYY-MM-DDTHH:MM2026-07-07T14:30min, max, step (seconds)
monthYYYY-MM2026-07min, max, step (months)
weekYYYY-Www2026-W28min, max, step (weeks)
timeHH:MM or HH:MM:SS14:30min, max, step (seconds)
datetime-inputs.html
HTML
1<!-- Date picker with min/max constraints -->
2<label for="appointment">Appointment Date</label>
3<input
4 type="date"
5 id="appointment"
6 name="appointment"
7 min="2026-07-01"
8 max="2026-12-31"
9 value="2026-07-15"
10 required
11/>
12
13<!-- Date and time (no timezone) -->
14<label for="meeting">Meeting Start</label>
15<input
16 type="datetime-local"
17 id="meeting"
18 name="meeting"
19 min="2026-07-07T09:00"
20 max="2026-07-07T17:00"
21 step="900"
22/>
23
24<!-- Month picker -->
25<label for="billing-month">Billing Month</label>
26<input
27 type="month"
28 id="billing-month"
29 name="billing-month"
30 min="2026-01"
31 max="2026-12"
32/>
33
34<!-- Week picker -->
35<label for="sprint-week">Sprint Week</label>
36<input
37 type="week"
38 id="sprint-week"
39 name="sprint-week"
40 min="2026-W01"
41 max="2026-W52"
42/>
43
44<!-- Time picker with step -->
45<label for="start-time">Start Time</label>
46<input
47 type="time"
48 id="start-time"
49 name="start-time"
50 min="09:00"
51 max="17:00"
52 step="1800"
53 value="09:00"
54/>
55
56<!-- Combining date and time into separate fields -->
57<label for="start-date">Departure Date</label>
58<input type="date" id="start-date" name="start-date" required />
59
60<label for="start-time">Departure Time</label>
61<input type="time" id="start-time" name="start-time" required />
🔥

pro tip

Use step="900" on time inputs to restrict selection to 15-minute intervals (900 seconds). The datetime-local value is formatted as YYYY-MM-DDTHH:MM (with a literal T separating date and time). For timezone-aware date/time, handle conversion on the server or use a JavaScript library like date-fns-tz.
File Inputs

The type="file" input opens the system file picker, letting users select files from their local device. The accept attribute filters allowed file types, multiple enables batch selection, and capture directs mobile browsers to the camera or microphone.

AttributeExampleDescription
acceptaccept="image/*,.pdf"Comma-separated MIME types or file extensions
multiplemultipleAllow selecting more than one file
capturecapture="environment"Direct camera/microphone access (mobile)
requiredrequiredForm cannot submit without a file
file-inputs.html
HTML
1<!-- Single image upload with format filter -->
2<label for="avatar">Profile Picture</label>
3<input
4 type="file"
5 id="avatar"
6 name="avatar"
7 accept="image/png,image/jpeg,image/webp"
8 required
9/>
10
11<!-- Multiple PDF upload -->
12<label for="documents">Upload Documents</label>
13<input
14 type="file"
15 id="documents"
16 name="documents"
17 multiple
18 accept=".pdf,.doc,.docx"
19/>
20
21<!-- Mobile camera capture -->
22<label for="photo">Take a Photo</label>
23<input
24 type="file"
25 id="photo"
26 name="photo"
27 accept="image/*"
28 capture="environment"
29/>
30
31<!-- File preview with File API -->
32<input type="file" id="fileInput" accept="image/*" />
33<img id="preview" alt="File preview" style="display:none;max-width:200px;margin-top:8px;" />
34
35<script>
36 const fileInput = document.getElementById('fileInput');
37 const preview = document.getElementById('preview');
38
39 fileInput.addEventListener('change', () => {
40 const file = fileInput.files[0];
41 if (file) {
42 const reader = new FileReader();
43 reader.onload = (e) => {
44 preview.src = e.target.result;
45 preview.style.display = 'block';
46 };
47 reader.readAsDataURL(file);
48 }
49 });
50</script>

warning

File inputs are read-only for security reasons — you cannot set their value via JavaScript. The capture attribute only works on mobile browsers. Always validate file types, sizes, and content on the server; client-side validation is easily bypassed. Use the multiple attribute sparingly — uploading many large files simultaneously can overwhelm the server.
Range & Color

The range input renders a slider for selecting a numeric value within a range. The color input opens the system color picker and returns a hexadecimal color value. Both provide native controls without JavaScript.

range-color.html
HTML
1<!-- Range slider with all attributes -->
2<label for="volume">Volume: <span id="volumeValue">65</span></label>
3<input
4 type="range"
5 id="volume"
6 name="volume"
7 min="0"
8 max="100"
9 step="1"
10 value="65"
11/>
12
13<script>
14 const volume = document.getElementById('volume');
15 const volumeValue = document.getElementById('volumeValue');
16 volume.addEventListener('input', () => {
17 volumeValue.textContent = volume.value;
18 });
19</script>
20
21<!-- Color picker -->
22<label for="theme-color">Theme Color</label>
23<input
24 type="color"
25 id="theme-color"
26 name="theme-color"
27 value="#00FF41"
28/>
29
30<!-- Range with custom step and dual value display -->
31<label for="price">Price: $<span id="priceValue">50</span></label>
32<input
33 type="range"
34 id="price"
35 name="price"
36 min="10"
37 max="200"
38 step="5"
39 value="50"
40/>
41<datalist id="price-ticks">
42 <option value="10" label="$10"></option>
43 <option value="50" label="$50"></option>
44 <option value="100" label="$100"></option>
45 <option value="150" label="$150"></option>
46 <option value="200" label="$200"></option>
47</datalist>
48
49<script>
50 const price = document.getElementById('price');
51 const priceValue = document.getElementById('priceValue');
52 price.addEventListener('input', () => {
53 priceValue.textContent = price.value;
54 });
55</script>
🔥

pro tip

The range input does not display its current value — you must use JavaScript to show it. The color input always returns a lowercase 7-character hex string (e.g., #00ff41). Use a <datalist> with option elements to add tick marks on the range slider.
Hidden Inputs

Hidden inputs (type="hidden") are invisible to the user but submit their value with the form. They are used to pass state, CSRF tokens, session identifiers, or configuration data that the server needs but the user should not see or modify. Despite being hidden in the UI, the value is visible in the HTML source and can be inspected with DevTools.

hidden-inputs.html
HTML
1<!-- CSRF token -->
2<form action="/submit" method="POST">
3 <input
4 type="hidden"
5 name="_csrf"
6 value="a1b2c3d4e5f6..."
7 />
8
9 <label for="message">Message</label>
10 <textarea id="message" name="message" required></textarea>
11 <button type="submit">Submit</button>
12</form>
13
14<!-- Page/session state -->
15<input
16 type="hidden"
17 name="page"
18 value="checkout-step-3"
19/>
20
21<!-- Timestamp for anti-spam -->
22<input
23 type="hidden"
24 name="form-loaded"
25 value="2026-07-07T14:30:00Z"
26/>
27
28<!-- User/session identifier -->
29<input
30 type="hidden"
31 name="session-id"
32 value="sess_abc123"
33/>
34
35<!-- Next/previous page for multi-step forms -->
36<input type="hidden" name="step" value="3" />
37<input type="hidden" name="return-url" value="/checkout/review" />

warning

Never put sensitive data (passwords, tokens, personal information) in hidden inputs. The value is visible in the HTML source and can be read by any script on the page. For CSRF protection, use server-generated tokens tied to the session, not static values. Hidden inputs are not a security mechanism — they are a convenience for passing non-sensitive state.
Input Attributes

Input attributes control validation constraints, user experience, autofill behavior, and styling. Combining these attributes correctly determines how the input behaves, how it is validated, and how it interacts with browser autofill.

AttributeApplies ToDescription
placeholdertext, search, email, url, tel, password, textareaHint text shown before input — not a substitute for a label
requiredMost input typesField must have a value before form submission
readonlytext, textarea, select, date, timeValue cannot be edited but is still submitted
disabledAll input typesNot editable, not submitted, grayed out
minlengthtext, email, url, tel, search, password, textareaMinimum character count
maxlengthtext, email, url, tel, search, password, textareaMaximum character count
patterntext, tel, email, url, search, passwordRegex pattern for validation
min / maxnumber, date, range, datetime-local, month, week, timeNumeric or date range constraints
stepnumber, date, range, datetime-local, month, week, timeIncrement granularity
autocompleteAll input typesBrowser autofill behavior (on, off, or specific token)
autofocusMost input typesAutomatically focus this input on page load (use once)
spellchecktext, textarea, searchEnable or disable spell checking
inputmodeAll input typesHint for the on-screen keyboard type
input-attributes.html
HTML
1<!-- Complete attribute example -->
2<label for="username">Username</label>
3<input
4 type="text"
5 id="username"
6 name="username"
7 placeholder="johndoe"
8 value=""
9 required
10 minlength="3"
11 maxlength="20"
12 pattern="[a-zA-Z0-9_]+"
13 title="Letters, numbers, and underscores only"
14 autocomplete="username"
15 autofocus
16 spellcheck="false"
17/>
18
19<!-- Readonly vs disabled -->
20<input type="text" value="Cannot edit" readonly />
21<input type="text" value="Grayed out" disabled />
22
23<!-- Number with min/max/step -->
24<label for="quantity">Quantity</label>
25<input
26 type="number"
27 id="quantity"
28 name="quantity"
29 min="1"
30 max="99"
31 step="1"
32 value="1"
33 required
34/>
35
36<!-- Email with inputmode hint -->
37<label for="email">Email</label>
38<input
39 type="email"
40 id="email"
41 name="email"
42 inputmode="email"
43 autocomplete="email"
44 required
45/>
46
47<!-- Date with constraints -->
48<label for="arrival">Arrival Date</label>
49<input
50 type="date"
51 id="arrival"
52 name="arrival"
53 min="2026-07-01"
54 max="2026-12-31"
55 required
56/>

best practice

Use autocomplete with specific tokens like "email", "tel", "given-name", and "address-line1" to enable browser autofill. Well-configured autocomplete significantly reduces form completion time on mobile. Only use autofocus on one element per page — typically the first field of a login or search form. Never use autofocus on long forms where it may scroll the page unexpectedly.
Styling Inputs

CSS pseudo-classes enable styling input states without JavaScript. The browser automatically applies classes like :valid, :invalid, :required, :disabled, and :focus. The newer :user-valid and :user-invalid pseudo-classes only apply after the user has interacted with the field.

input-styling.css
CSS
1/* Base input styling */
2input, textarea, select {
3 font-family: inherit;
4 font-size: 14px;
5 padding: 10px 12px;
6 border: 1px solid #d1d5db;
7 border-radius: 6px;
8 background: #fff;
9 color: #1a1a1a;
10 transition: border-color 0.2s, box-shadow 0.2s;
11 outline: none;
12 width: 100%;
13}
14
15/* Focus state */
16input:focus {
17 border-color: #3b82f6;
18 box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
19}
20
21/* Valid state */
22input:valid {
23 border-color: #22c55e;
24}
25
26/* Invalid state (before user interaction) */
27input:invalid {
28 border-color: #d1d5db;
29}
30
31/* User-interacted invalid */
32input:user-invalid {
33 border-color: #ef4444;
34 box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.15);
35}
36
37/* User-interacted valid */
38input:user-valid {
39 border-color: #22c55e;
40 box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.15);
41}
42
43/* Disabled */
44input:disabled {
45 opacity: 0.5;
46 cursor: not-allowed;
47 background: #f9fafb;
48}
49
50/* Readonly */
51input:read-only {
52 border-style: dashed;
53 background: #f9fafb;
54}
55
56/* Placeholder styling */
57input::placeholder {
58 color: #9ca3af;
59}
60
61/* Required indicator */
62input:required + .label-text::after {
63 content: " *";
64 color: #ef4444;
65}
66
67/* Range slider cross-browser */
68input[type="range"] {
69 -webkit-appearance: none;
70 appearance: none;
71 height: 6px;
72 background: #e5e7eb;
73 border-radius: 3px;
74 padding: 0;
75}
76
77input[type="range"]::-webkit-slider-thumb {
78 -webkit-appearance: none;
79 appearance: none;
80 width: 18px;
81 height: 18px;
82 border-radius: 50%;
83 background: #3b82f6;
84 cursor: pointer;
85 border: 2px solid #fff;
86 box-shadow: 0 1px 3px rgba(0,0,0,0.2);
87}
🔥

pro tip

The :user-valid and :user-invalid pseudo-classes are relatively new but widely supported. They only apply after the user has interacted with the field — preventing red error borders on empty required fields before the user has had a chance to type. Use them as a progressive enhancement over the basic :valid/:invalid selectors.
Accessibility

Accessible input controls ensure all users — including those using screen readers or keyboard navigation — can successfully interact with forms. The foundation is proper labeling with <label>, descriptive error messages linked via aria-describedby, and invalid state indicators via aria-invalid.

TechniqueImplementationPurpose
Explicit label<label for="id">Text</label>Associates label with input via matching for/id
Implicit label<label><input>Text</label>Wraps input inside label element
aria-labelaria-label="Search"Label when no visible text is possible
aria-describedbyaria-describedby="hint-id error-id"Links input to help text or error message
aria-invalidaria-invalid="true"Indicates the field has a validation error
aria-requiredaria-required="true"Announces field as required to screen reader
role="alert"role="alert" on error containerImmediately announces dynamic error content
Fieldset/legend<fieldset><legend>Groups related inputs with a shared label
accessible-inputs.html
HTML
1<!-- Properly labeled form with error handling -->
2<form id="signupForm" novalidate>
3 <fieldset>
4 <legend>Account Information</legend>
5
6 <label for="signup-name">Full Name</label>
7 <input
8 type="text"
9 id="signup-name"
10 name="name"
11 required
12 minlength="2"
13 aria-required="true"
14 aria-describedby="name-hint name-error"
15 />
16 <span id="name-hint" class="hint">
17 Enter your full name (min 2 characters)
18 </span>
19 <span id="name-error" class="error" role="alert"></span>
20
21 <label for="signup-email">Email Address</label>
22 <input
23 type="email"
24 id="signup-email"
25 name="email"
26 required
27 aria-required="true"
28 aria-describedby="email-error"
29 />
30 <span id="email-error" class="error" role="alert"></span>
31 </fieldset>
32
33 <button type="submit">Create Account</button>
34</form>
35
36<script>
37 const form = document.getElementById('signupForm');
38 form.addEventListener('submit', (e) => {
39 e.preventDefault();
40 let hasError = false;
41
42 const nameInput = document.getElementById('signup-name');
43 const nameError = document.getElementById('name-error');
44 const emailInput = document.getElementById('signup-email');
45 const emailError = document.getElementById('email-error');
46
47 // Validate name
48 if (!nameInput.checkValidity()) {
49 nameError.textContent = 'Name is required (min 2 characters)';
50 nameInput.setAttribute('aria-invalid', 'true');
51 hasError = true;
52 } else {
53 nameError.textContent = '';
54 nameInput.removeAttribute('aria-invalid');
55 }
56
57 // Validate email
58 if (!emailInput.checkValidity()) {
59 emailError.textContent = 'A valid email is required';
60 emailInput.setAttribute('aria-invalid', 'true');
61 hasError = true;
62 } else {
63 emailError.textContent = '';
64 emailInput.removeAttribute('aria-invalid');
65 }
66
67 if (!hasError) {
68 alert('Form submitted successfully!');
69 }
70 });
71</script>

best practice

Always use native <label> elements with explicit for attributes. This is the most widely supported and reliable method for associating labels with inputs. Reserve aria-label for cases where no visible label is possible (icon-only controls). Use aria-describedby to link help text and error messages to the input — screen readers announce described-by content when the input receives focus.

Live preview of an accessible form with labels, hints, and validation:

preview
$Blueprint — Engineering Documentation·Section ID: HTML-20·Revision: 1.0