HTML Forms and Input Controls
1. Form Element and Form Attributes
| Attribute | Purpose | Values | Default |
|---|---|---|---|
| action | URL to submit form data | URL or relative path | Current page |
| method | HTTP method for submission | GET, POST, DIALOG |
GET |
| enctype | Form data encoding type | application/x-www-form-urlencoded, multipart/form-data, text/plain | application/x-www-form-urlencoded |
| target | Where to display response | _self, _blank, _parent, _top |
_self |
| autocomplete | Enable autofill | on, off |
on |
| novalidate | Disable HTML5 validation | Boolean | false |
| name | Form identifier | String | None |
| accept-charset | Character encodings | Space-separated list (e.g., UTF-8) | Page encoding |
| rel | Link relationship | noopener, noreferrer |
None |
Example: Form element with various attributes
<!-- Basic form -->
<form action="/submit" method="POST">
<!-- Form fields here -->
<button type="submit">Submit</button>
</form>
<!-- File upload form -->
<form action="/upload" method="POST" enctype="multipart/form-data">
<input type="file" name="document">
<button type="submit">Upload</button>
</form>
<!-- Search form (GET) -->
<form action="/search" method="GET">
<input type="search" name="q" placeholder="Search...">
<button type="submit">Search</button>
</form>
<!-- Form with autocomplete disabled -->
<form action="/payment" method="POST" autocomplete="off">
<input type="text" name="card-number">
<button type="submit">Pay</button>
</form>
<!-- Form without HTML5 validation -->
<form action="/custom" method="POST" novalidate>
<input type="email" name="email">
<button type="submit">Submit</button>
</form>
<!-- Form opening in new tab -->
<form action="/external" method="POST" target="_blank" rel="noopener">
<button type="submit">Open in New Tab</button>
</form>
Note: Use
POST for forms that modify data. Use
enctype="multipart/form-data" for file uploads. Add rel="noopener" when using
target="_blank" for security.
2. Input Types and HTML5 Form Controls
| Input Type | Purpose | Mobile Keyboard | Validation |
|---|---|---|---|
| text | Single-line text | Standard | Length, pattern |
| Email address | @ key visible | Email format | |
| tel | Telephone number | Numeric keypad | Pattern only |
| url | Web address | .com, / keys | URL format |
| number | Numeric input | Numeric + - keys | Min, max, step |
| range | Slider control | N/A | Min, max, step |
| date | Date picker | Date picker | Min, max |
| time | Time picker | Time picker | Min, max, step |
| datetime-local | Date + time picker | Date/time picker | Min, max |
| month | Month + year | Month picker | Min, max |
| week | Week number | Week picker | Min, max |
| color | Color picker | Color palette | Hex format |
| search | Search field | Search button | Length, pattern |
| password | Password (hidden) | Standard | Length, pattern |
| file | File upload | File browser | Accept types |
| checkbox | Boolean toggle | N/A | Required |
| radio | Single choice from group | N/A | Required |
| submit | Submit button | N/A | N/A |
| reset | Reset form values | N/A | N/A |
| button | Generic button | N/A | N/A |
| hidden | Hidden field | N/A | None |
| image | Image submit button | N/A | N/A |
Example: Common input types
<!-- Text inputs -->
<input type="text" name="username" placeholder="Username">
<input type="email" name="email" placeholder="email@example.com">
<input type="tel" name="phone" placeholder="(555) 123-4567">
<input type="url" name="website" placeholder="https://example.com">
<input type="password" name="password" placeholder="Password">
<input type="search" name="query" placeholder="Search...">
<!-- Number and range -->
<input type="number" name="age" min="0" max="120" step="1">
<input type="range" name="volume" min="0" max="100" value="50">
<!-- Date and time -->
<input type="date" name="birthday" min="1900-01-01" max="2024-12-31">
<input type="time" name="appointment" step="900"> <!-- 15 min steps -->
<input type="datetime-local" name="meeting">
<input type="month" name="start-month">
<input type="week" name="week-number">
<!-- Color picker -->
<input type="color" name="theme-color" value="#007acc">
<!-- File upload -->
<input type="file" name="document" accept=".pdf,.doc,.docx">
<input type="file" name="photos" accept="image/*" multiple>
<!-- Checkboxes -->
<input type="checkbox" name="subscribe" id="subscribe" checked>
<label for="subscribe">Subscribe to newsletter</label>
<!-- Radio buttons -->
<input type="radio" name="plan" id="free" value="free" checked>
<label for="free">Free</label>
<input type="radio" name="plan" id="pro" value="pro">
<label for="pro">Pro</label>
<!-- Hidden field -->
<input type="hidden" name="csrf_token" value="abc123">
<!-- Buttons -->
<input type="submit" value="Submit Form">
<input type="reset" value="Reset">
<input type="button" value="Click Me" onclick="alert('Clicked')">
Warning: Never use
type="reset" unless absolutely necessary - users often click it
by mistake. Use type="tel" instead of type="number" for phone numbers to avoid spinner
controls.
3. Select, Option, and Datalist Elements
| Element | Purpose | Key Attributes | Use Case |
|---|---|---|---|
| <select> | Dropdown menu | name, multiple, size, required, disabled | Single/multiple choice from list |
| <option> | Dropdown item | value, selected, disabled, label | Individual choice option |
| <optgroup> | Group options | label, disabled | Organize related options |
| <datalist> | Autocomplete suggestions | id (referenced by input list) | Type-ahead suggestions |
Example: Select, option, optgroup, and datalist
<!-- Basic select dropdown -->
<select name="country">
<option value="">Select a country</option>
<option value="us">United States</option>
<option value="uk">United Kingdom</option>
<option value="ca">Canada</option>
</select>
<!-- With optgroup -->
<select name="car">
<optgroup label="European Cars">
<option value="bmw">BMW</option>
<option value="mercedes">Mercedes</option>
</optgroup>
<optgroup label="American Cars">
<option value="ford">Ford</option>
<option value="tesla">Tesla</option>
</optgroup>
</select>
<!-- Multiple selection -->
<select name="skills" multiple size="5">
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="js" selected>JavaScript</option>
<option value="react">React</option>
<option value="node">Node.js</option>
</select>
<!-- With disabled options -->
<select name="plan">
<option value="free">Free</option>
<option value="pro" selected>Pro</option>
<option value="enterprise" disabled>Enterprise (Contact Sales)</option>
</select>
<!-- Datalist (autocomplete suggestions) -->
<input type="text" name="browser" list="browsers" placeholder="Choose browser">
<datalist id="browsers">
<option value="Chrome">
<option value="Firefox">
<option value="Safari">
<option value="Edge">
<option value="Opera">
</datalist>
<!-- Datalist with descriptions -->
<input type="text" name="city" list="cities">
<datalist id="cities">
<option value="New York">NY, USA</option>
<option value="London">UK</option>
<option value="Tokyo">Japan</option>
</datalist>
Note: Always include an empty
<option> with placeholder text for required
selects. Use <optgroup> to organize long lists. Datalist provides suggestions but allows
custom input.
4. Textarea and Multi-line Input
| Attribute | Purpose | Values | Default |
|---|---|---|---|
| rows | Visible text lines | Number (e.g., 4) | 2 |
| cols | Visible character width | Number (e.g., 50) | 20 |
| maxlength | Maximum character count | Number | Unlimited |
| minlength | Minimum character count | Number | 0 |
| placeholder | Placeholder text | String | None |
| readonly | Read-only (not editable) | Boolean | false |
| disabled | Disabled (not submitted) | Boolean | false |
| required | Must be filled | Boolean | false |
| wrap | Text wrapping behavior | soft, hard |
soft |
| autocomplete | Autofill behavior | on, off |
on |
| spellcheck | Spell checking | true, false |
true |
Wrap Values
| Value | Behavior |
|---|---|
| soft | Text wraps visually, no line breaks in submitted data |
| hard | Text wraps and includes line breaks in submission |
Sizing Best Practices:
- Use CSS
widthandheightinstead of cols/rows for responsive design - Set
resize: verticalto allow vertical resizing only - Set
resize: noneto disable resizing - Default allows both horizontal and vertical resizing
Example: Textarea configurations
<!-- Basic textarea -->
<textarea name="comments" rows="4" cols="50" placeholder="Enter your comments..."></textarea>
<!-- With character limit -->
<textarea name="bio" rows="3" maxlength="200" placeholder="Bio (max 200 characters)"></textarea>
<!-- Required with minimum length -->
<textarea name="description" rows="5" required minlength="20"
placeholder="Provide a detailed description (min 20 characters)"></textarea>
<!-- Read-only textarea -->
<textarea name="terms" rows="10" readonly>
Terms and Conditions...
User must read but cannot edit.
</textarea>
<!-- Disabled textarea -->
<textarea name="disabled-field" rows="3" disabled>
This field is disabled and won't be submitted.
</textarea>
<!-- Hard wrap (preserves line breaks) -->
<textarea name="message" rows="5" wrap="hard" cols="40"></textarea>
<!-- CSS-styled textarea -->
<textarea name="notes" style="width: 100%; max-width: 600px; resize: vertical;"
rows="6" placeholder="Notes..."></textarea>
<!-- Disable spell check -->
<textarea name="code" rows="10" spellcheck="false"
placeholder="Paste code here..."></textarea>
<!-- With character counter (requires JavaScript) -->
<textarea name="tweet" id="tweet" rows="3" maxlength="280"
oninput="updateCounter()"></textarea>
<p><span id="counter">0</span>/280 characters</p>
<script>
function updateCounter() {
const textarea = document.getElementById('tweet');
const counter = document.getElementById('counter');
counter.textContent = textarea.value.length;
}
</script>
Note: Unlike
<input>, textarea content goes between opening and closing
tags, not in a value attribute. Use CSS for responsive sizing instead of
rows/cols.
5. Fieldset, Legend, and Form Grouping
| Element | Purpose | Key Attributes | Accessibility |
|---|---|---|---|
| <fieldset> | Group related form controls | disabled, form, name | Creates logical grouping for screen readers |
| <legend> | Caption for fieldset | None (first child of fieldset) | Announces group name to screen readers |
Fieldset Attributes
| Attribute | Purpose |
|---|---|
| disabled | Disables all controls within fieldset |
| form | Associates fieldset with form (by form id) |
| name | Name for the fieldset |
Use Cases:
- Radio button groups - Group related options
- Checkbox groups - Related checkboxes
- Address sections - Street, city, zip
- Contact info - Phone, email, etc.
- Payment details - Card, billing address
- Multi-step forms - Logical sections
Example: Fieldset and legend usage
<!-- Radio button group -->
<fieldset>
<legend>Select Payment Method</legend>
<input type="radio" name="payment" id="card" value="card" checked>
<label for="card">Credit Card</label><br>
<input type="radio" name="payment" id="paypal" value="paypal">
<label for="paypal">PayPal</label><br>
<input type="radio" name="payment" id="bank" value="bank">
<label for="bank">Bank Transfer</label>
</fieldset>
<!-- Checkbox group -->
<fieldset>
<legend>Select Interests</legend>
<input type="checkbox" name="interests" id="coding" value="coding">
<label for="coding">Coding</label><br>
<input type="checkbox" name="interests" id="design" value="design">
<label for="design">Design</label><br>
<input type="checkbox" name="interests" id="marketing" value="marketing">
<label for="marketing">Marketing</label>
</fieldset>
<!-- Address form section -->
<fieldset>
<legend>Shipping Address</legend>
<label for="street">Street:</label>
<input type="text" id="street" name="street"><br>
<label for="city">City:</label>
<input type="text" id="city" name="city"><br>
<label for="zip">ZIP:</label>
<input type="text" id="zip" name="zip">
</fieldset>
<!-- Disabled fieldset -->
<fieldset disabled>
<legend>Premium Features (Upgrade Required)</legend>
<input type="checkbox" name="feature1" id="feature1">
<label for="feature1">Advanced Analytics</label><br>
<input type="checkbox" name="feature2" id="feature2">
<label for="feature2">Priority Support</label>
</fieldset>
<!-- Nested fieldsets -->
<form>
<fieldset>
<legend>Account Information</legend>
<fieldset>
<legend>Personal Details</legend>
<input type="text" name="firstname" placeholder="First Name">
<input type="text" name="lastname" placeholder="Last Name">
</fieldset>
<fieldset>
<legend>Contact Information</legend>
<input type="email" name="email" placeholder="Email">
<input type="tel" name="phone" placeholder="Phone">
</fieldset>
</fieldset>
</form>
Note: Always use
<fieldset> and <legend> for radio button
groups - it's essential for accessibility. Screen readers announce the legend
when focusing on any control within the fieldset.
6. Label Association and Accessibility
| Association Method | Syntax | Use Case | Clickable |
|---|---|---|---|
| Explicit (for/id) | <label for="inputId">...</label> |
Separate label and input | Yes |
| Implicit (wrapping) | <label>Text <input></label> |
Label wraps input | Yes |
| aria-label | <input aria-label="Description"> |
No visible label | No |
| aria-labelledby | <input aria-labelledby="id1 id2"> |
Reference existing element(s) | No |
Benefits:
- Clickable target area - Easier to interact
- Screen reader support - Announces label
- Focus management - Clicking label focuses input
- Better mobile UX - Larger touch targets
Example: Label association methods
<!-- Explicit association (for/id) - Recommended -->
<label for="username">Username:</label>
<input type="text" id="username" name="username">
<!-- Implicit association (wrapping) -->
<label>
Email:
<input type="email" name="email">
</label>
<!-- Checkbox with explicit label -->
<input type="checkbox" id="terms" name="terms">
<label for="terms">I agree to the terms and conditions</label>
<!-- Radio buttons with labels -->
<input type="radio" name="size" id="small" value="S">
<label for="small">Small</label>
<input type="radio" name="size" id="medium" value="M">
<label for="medium">Medium</label>
<input type="radio" name="size" id="large" value="L">
<label for="large">Large</label>
<!-- Multiple labels for one input -->
<label for="price">Price:</label>
<input type="number" id="price" name="price" aria-describedby="price-help">
<small id="price-help">Enter amount in USD</small>
<!-- aria-label (no visible label) -->
<input type="search" aria-label="Search products" placeholder="Search...">
<!-- aria-labelledby (reference existing elements) -->
<h3 id="card-heading">Credit Card Information</h3>
<input type="text" aria-labelledby="card-heading" placeholder="Card number">
<!-- Required field indication -->
<label for="email-required">
Email: <span aria-label="required">*</span>
</label>
<input type="email" id="email-required" name="email" required>
<!-- Label with help text -->
<label for="password">
Password:
<span style="font-weight: normal; font-size: 0.9em;">(min 8 characters)</span>
</label>
<input type="password" id="password" name="password" minlength="8">
Warning: Every form input must have an associated label for
accessibility. Never rely solely on
placeholder - it disappears when typing and isn't read by all
screen readers. Use aria-label only when a visible label isn't possible.
7. Form Validation Attributes and Patterns
| Attribute | Applies To | Purpose | Validation Type |
|---|---|---|---|
| required | Most inputs, select, textarea | Field must not be empty | Presence |
| minlength | text, email, url, tel, password, search, textarea | Minimum character count | Length |
| maxlength | text, email, url, tel, password, search, textarea | Maximum character count | Length |
| min | number, range, date, time, datetime-local, month, week | Minimum value | Range |
| max | number, range, date, time, datetime-local, month, week | Maximum value | Range |
| step | number, range, date, time, datetime-local, month, week | Valid increment intervals | Granularity |
| pattern | text, email, url, tel, password, search | Regular expression validation | Format |
| type | input | Built-in validation (email, url, number, etc.) | Type-specific |
| accept | file | Allowed file types | File type |
| multiple | email, file | Allow multiple values | Quantity |
Example: Form validation attributes
<form>
<!-- Required field -->
<label for="name">Name (required):</label>
<input type="text" id="name" name="name" required>
<!-- Length validation -->
<label for="username">Username (3-15 characters):</label>
<input type="text" id="username" name="username"
minlength="3" maxlength="15" required>
<!-- Number range -->
<label for="age">Age (18-100):</label>
<input type="number" id="age" name="age"
min="18" max="100" required>
<!-- Step validation -->
<label for="donation">Donation (multiples of $5):</label>
<input type="number" id="donation" name="donation"
min="5" step="5">
<!-- Date range -->
<label for="appointment">Appointment Date:</label>
<input type="date" id="appointment" name="appointment"
min="2024-01-01" max="2024-12-31" required>
<!-- Pattern: ZIP code -->
<label for="zip">ZIP Code:</label>
<input type="text" id="zip" name="zip"
pattern="[0-9]{5}"
title="5-digit ZIP code"
placeholder="12345" required>
<!-- Pattern: Phone number -->
<label for="phone">Phone:</label>
<input type="tel" id="phone" name="phone"
pattern="\d{3}-\d{3}-\d{4}"
title="Format: 555-123-4567"
placeholder="555-123-4567">
<!-- Pattern: Username (alphanumeric + underscore) -->
<label for="user">Username:</label>
<input type="text" id="user" name="user"
pattern="[a-zA-Z0-9_]{4,16}"
title="4-16 characters: letters, numbers, underscore only">
<!-- Pattern: Strong password -->
<label for="password">Password:</label>
<input type="password" id="password" name="password"
pattern="^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$"
title="Min 8 chars, at least one letter, number, and special character"
required>
<!-- Multiple emails -->
<label for="emails">Email Addresses (comma-separated):</label>
<input type="email" id="emails" name="emails" multiple>
<!-- File type validation -->
<label for="document">Upload Document:</label>
<input type="file" id="document" name="document"
accept=".pdf,.doc,.docx" required>
<!-- Image files only -->
<label for="photo">Upload Photo:</label>
<input type="file" id="photo" name="photo"
accept="image/*">
<button type="submit">Submit</button>
</form>
<!-- CSS for validation states -->
<style>
input:valid {
border-color: green;
}
input:invalid {
border-color: red;
}
input:required {
border-left: 3px solid orange;
}
</style>
Note: Always include
title attribute with pattern to provide
user-friendly error messages. Browser default messages can be cryptic. Use :invalid CSS
pseudo-class carefully - it triggers before user interaction.
Section 7 Key Takeaways
- Use
POSTfor data modification,GETfor search/filtering - Set
enctype="multipart/form-data"for file uploads - Use appropriate input types (email, tel, url, date) for mobile keyboard optimization
- Always associate labels with inputs using
for/idfor accessibility - Wrap radio button groups in
<fieldset>with<legend> - Use
patternwithtitlefor custom validation with user-friendly messages - Avoid
type="reset"- users often click it by mistake - Provide visible labels - don't rely solely on
placeholdertext