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

Method Comparison

Method Use Case Visible in URL
GET Search forms, filters, idempotent actions Yes
POST Create/update data, file uploads, sensitive data No
DIALOG Close dialog without submission N/A

Enctype Values

Type Use Case
application/x-www-form-urlencoded Default, standard forms
multipart/form-data File uploads
text/plain Debugging (not recommended)

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 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

Select Attributes

Attribute Purpose
name Form field identifier
multiple Allow multiple selections
size Visible options (default: 1)
required Must select an option
disabled Disable entire select
autocomplete Browser autofill behavior

Option Attributes

Attribute Purpose
value Submitted value
selected Pre-selected option
disabled Non-selectable option
label Alternative display text

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 width and height instead of cols/rows for responsive design
  • Set resize: vertical to allow vertical resizing only
  • Set resize: none to 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

Label Attributes

Attribute Purpose
for Associates with input id
form Associates with form id
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

Common Patterns

Pattern Use Case
[0-9]{5} 5-digit ZIP code
[A-Za-z]{3,} 3+ letters only
\d{3}-\d{3}-\d{4} Phone: 555-123-4567
[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$ Email format
^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$ Password: 8+ chars, letter+digit

Validation States (CSS)

Pseudo-class State
:valid Passes validation
:invalid Fails validation
:required Has required attribute
:optional Not required
:in-range Within min/max
:out-of-range Outside min/max

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 POST for data modification, GET for 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/id for accessibility
  • Wrap radio button groups in <fieldset> with <legend>
  • Use pattern with title for custom validation with user-friendly messages
  • Avoid type="reset" - users often click it by mistake
  • Provide visible labels - don't rely solely on placeholder text