2.6: Forms & Input Elements

Build interactive forms with input elements, validation, and proper labeling for accessibility. Learn form structure, input types, and how to handle user data submission.

1. Basic Form Structure

The <form> Element

<form action="/submit" method="POST">
  <label for="username">Username:</label>
  <input type="text" id="username" name="username">

  <button type="submit">Submit</button>
</form>

Form attributes:

  • action - URL where form data is sent
  • method - HTTP method (GET or POST)
  • enctype - Encoding type (for file uploads: multipart/form-data)
  • autocomplete - Enable/disable browser autocomplete
  • novalidate - Disable browser validation

GET vs POST

GET method:

<form action="/search" method="GET">
  <input type="text" name="q" placeholder="Search...">
  <button type="submit">Search</button>
</form>

Result: https://example.com/search?q=html+forms

When to use GET:

  • Search forms
  • Filters and sorting
  • Bookmarkable URLs
  • Read-only operations

POST method:

<form action="/login" method="POST">
  <input type="email" name="email">
  <input type="password" name="password">
  <button type="submit">Log In</button>
</form>

Result: Data sent in request body (not visible in URL)

When to use POST:

  • Sensitive data (passwords, personal info)
  • Large amounts of data
  • File uploads
  • Data modification (create, update, delete)

2. Labels and Accessibility

The <label> Element

Two ways to associate labels with inputs:

Method 1: for attribute (recommended)

<label for="email">Email Address:</label>
<input type="email" id="email" name="email">

Method 2: Wrapping (implicit)

<label>
  Email Address:
  <input type="email" name="email">
</label>

Benefits of labels:

  • Clicking label focuses input (larger click target)
  • Screen readers announce label
  • Better accessibility
  • Required for good UX

Always Use Labels


<input type="text" placeholder="Enter your name">

<label for="name">Name:</label>
<input type="text" id="name" name="name" placeholder="Enter your name">

3. Text Input Types

Text Input

<label for="username">Username:</label>
<input type="text" id="username" name="username" required>

Email Input

<label for="email">Email:</label>
<input type="email" id="email" name="email" required>

Benefits:

  • Mobile keyboards show @ key
  • Built-in validation (checks for @ symbol)

Password Input

<label for="password">Password:</label>
<input type="password" id="password" name="password" required minlength="8">

Displays: •••••••• (hidden characters)

URL Input

<label for="website">Website:</label>
<input type="url" id="website" name="website" placeholder="https://example.com">

Benefits:

  • Validates URL format
  • Mobile keyboards optimized for URLs

Tel (Telephone) Input

<label for="phone">Phone:</label>
<input type="tel" id="phone" name="phone" pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}">

Benefits:

  • Mobile keyboards show number pad
  • Can use pattern for specific formats

Search Input

<label for="search">Search:</label>
<input type="search" id="search" name="q" placeholder="Search...">

Benefits:

  • Shows clear (×) button in some browsers
  • Semantic meaning for search

4. Number and Range Inputs

Number Input

<label for="quantity">Quantity:</label>
<input type="number" id="quantity" name="quantity" min="1" max="100" step="1" value="1">

Attributes:

  • min - Minimum value
  • max - Maximum value
  • step - Increment (default: 1)
  • value - Default value

Example: Price

<label for="price">Price:</label>
<input type="number" id="price" name="price" min="0" step="0.01" placeholder="0.00">

Range (Slider) Input

<label for="volume">Volume:</label>
<input type="range" id="volume" name="volume" min="0" max="100" value="50">
<output for="volume">50</output>

<script>
const volumeSlider = document.getElementById('volume')
const volumeOutput = document.querySelector('output[for="volume"]')

volumeSlider.addEventListener('input', (e) => {
  volumeOutput.textContent = e.target.value
})
</script>

Displays: Slider control (visual)


5. Date and Time Inputs

Date Input

<label for="birthdate">Birth Date:</label>
<input type="date" id="birthdate" name="birthdate" min="1900-01-01" max="2024-12-31">

Value format: YYYY-MM-DD

Time Input

<label for="appointment">Appointment Time:</label>
<input type="time" id="appointment" name="appointment" min="09:00" max="17:00" step="900">

Value format: HH:MM (24-hour) step="900" = 15-minute intervals (900 seconds)

Datetime-local Input

<label for="meeting">Meeting Date & Time:</label>
<input type="datetime-local" id="meeting" name="meeting">

Value format: YYYY-MM-DDTHH:MM

Month Input

<label for="exp-month">Expiry Month:</label>
<input type="month" id="exp-month" name="exp_month">

Value format: YYYY-MM

Week Input

<label for="week">Select Week:</label>
<input type="week" id="week" name="week">

Value format: YYYY-W## (e.g., 2024-W42)


6. Choice Inputs

Checkbox (Multiple Selection)

<fieldset>
  <legend>Select your 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="marketing">
    Marketing
  </label>
</fieldset>

Attributes:

  • checked - Pre-select checkbox
  • value - Value sent to server
  • name - Same name for related checkboxes

Radio Buttons (Single Selection)

<fieldset>
  <legend>Select your experience level:</legend>

  <label>
    <input type="radio" name="level" value="beginner" checked>
    Beginner
  </label>

  <label>
    <input type="radio" name="level" value="intermediate">
    Intermediate
  </label>

  <label>
    <input type="radio" name="level" value="advanced">
    Advanced
  </label>
</fieldset>

Key difference from checkbox:

  • Same name attribute groups radio buttons
  • Only one can be selected at a time

Select Dropdown

<label for="country">Country:</label>
<select id="country" name="country" required>
  <option value="">-- Select Country --</option>
  <option value="us">United States</option>
  <option value="uk">United Kingdom</option>
  <option value="ca">Canada</option>
  <option value="au">Australia</option>
</select>

With optgroups:

<label for="car">Choose a car:</label>
<select id="car" name="car">
  <optgroup label="German Cars">
    <option value="mercedes">Mercedes</option>
    <option value="audi">Audi</option>
    <option value="bmw">BMW</option>
  </optgroup>
  <optgroup label="Japanese Cars">
    <option value="toyota">Toyota</option>
    <option value="honda">Honda</option>
    <option value="nissan">Nissan</option>
  </optgroup>
</select>

Multiple selection:

<label for="languages">Languages you know:</label>
<select id="languages" name="languages" multiple size="5">
  <option value="html">HTML</option>
  <option value="css">CSS</option>
  <option value="js">JavaScript</option>
  <option value="python">Python</option>
  <option value="java">Java</option>
</select>

7. Text Area

Multi-line text input:

<label for="message">Message:</label>
<textarea
  id="message"
  name="message"
  rows="5"
  cols="50"
  maxlength="500"
  placeholder="Enter your message here..."
  required
></textarea>

<p><span id="char-count">0</span> / 500 characters</p>

<script>
const textarea = document.getElementById('message')
const charCount = document.getElementById('char-count')

textarea.addEventListener('input', (e) => {
  charCount.textContent = e.target.value.length
})
</script>

Attributes:

  • rows - Visible rows (height)
  • cols - Visible columns (width)
  • maxlength - Maximum character count
  • placeholder - Placeholder text

Note: Don't put spaces between opening and closing tags:


<textarea>
  Default text
</textarea>

<textarea>Default text</textarea>

8. File Upload

<label for="avatar">Choose profile picture:</label>
<input type="file" id="avatar" name="avatar" accept="image/png, image/jpeg">

Multiple files:

<label for="documents">Upload documents:</label>
<input type="file" id="documents" name="documents" multiple accept=".pdf,.doc,.docx">

Attributes:

  • accept - Allowed file types (MIME types or extensions)
  • multiple - Allow multiple files
  • capture - Use device camera (mobile): capture="user" (front) or capture="environment" (back)

Important: Form must have enctype="multipart/form-data" for file uploads:

<form action="/upload" method="POST" enctype="multipart/form-data">
  <label for="file">Choose file:</label>
  <input type="file" id="file" name="file">
  <button type="submit">Upload</button>
</form>

9. Other Input Types

Color Picker

<label for="color">Choose color:</label>
<input type="color" id="color" name="color" value="#ff0000">

Displays: Native color picker

Hidden Input

<input type="hidden" name="user_id" value="12345">

Use cases:

  • Passing data without displaying it
  • CSRF tokens
  • Session IDs

10. Fieldsets and Legends

Group related form fields:

<form>
  <fieldset>
    <legend>Personal Information</legend>

    <label for="fname">First Name:</label>
    <input type="text" id="fname" name="fname" required>

    <label for="lname">Last Name:</label>
    <input type="text" id="lname" name="lname" required>

    <label for="email">Email:</label>
    <input type="email" id="email" name="email" required>
  </fieldset>

  <fieldset>
    <legend>Shipping Address</legend>

    <label for="street">Street:</label>
    <input type="text" id="street" name="street" required>

    <label for="city">City:</label>
    <input type="text" id="city" name="city" required>

    <label for="zip">ZIP Code:</label>
    <input type="text" id="zip" name="zip" required>
  </fieldset>

  <button type="submit">Submit</button>
</form>

Benefits:

  • Visual grouping (border around fields)
  • Semantic structure
  • Screen readers announce group name
  • Can disable entire fieldset: <fieldset disabled>

11. Form Validation

Required Fields

<input type="text" name="username" required>
<input type="email" name="email" required>

Browser displays error if empty on submit

Pattern Validation (Regular Expressions)


<input
  type="tel"
  name="phone"
  pattern="\([0-9]{3}\) [0-9]{3}-[0-9]{4}"
  placeholder="(123) 456-7890"
  required
>

<input
  type="text"
  name="username"
  pattern="[a-zA-Z0-9]{3,16}"
  title="Username must be 3-16 alphanumeric characters"
  required
>

<input
  type="text"
  name="zip"
  pattern="[0-9]{5}"
  placeholder="12345"
  required
>

title attribute: Displays validation message

Min/Max Length

<input type="password" name="password" minlength="8" maxlength="20" required>
<textarea name="bio" minlength="50" maxlength="500"></textarea>

Min/Max Values (Numbers, Dates)

<input type="number" name="age" min="18" max="120" required>
<input type="date" name="start_date" min="2024-01-01" max="2024-12-31">

Custom Validation Messages

<input
  type="email"
  id="email"
  name="email"
  required
  oninvalid="this.setCustomValidity('Please enter a valid email address')"
  oninput="this.setCustomValidity('')"
>

Disable Validation


<form novalidate>
  
</form>

<button type="submit" formnovalidate>Save Draft</button>

12. Button Types

Submit Button

<button type="submit">Submit Form</button>

<input type="submit" value="Submit Form">

Reset Button

<button type="reset">Clear Form</button>

Clears all form fields to default values

Regular Button (No Default Action)

<button type="button" onclick="doSomething()">Click Me</button>

Use for JavaScript actions without form submission

Image Button

<input type="image" src="submit-button.png" alt="Submit">

Acts as submit button with custom image


13. Form Styling

Basic Form Layout

<form class="contact-form">
  <div class="form-group">
    <label for="name">Name:</label>
    <input type="text" id="name" name="name" required>
  </div>

  <div class="form-group">
    <label for="email">Email:</label>
    <input type="email" id="email" name="email" required>
  </div>

  <div class="form-group">
    <label for="message">Message:</label>
    <textarea id="message" name="message" rows="5" required></textarea>
  </div>

  <button type="submit">Send Message</button>
</form>

<style>
.contact-form {
  max-width: 600px;
  margin: 2rem auto;
  padding: 2rem;
  background: #f9f9f9;
  border-radius: 8px;
}

.form-group {
  margin-bottom: 1.5rem;
}

.form-group label {
  display: block;
  margin-bottom: 0.5rem;
  font-weight: bold;
  color: #333;
}

.form-group input,
.form-group textarea {
  width: 100%;
  padding: 0.75rem;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 1rem;
  font-family: inherit;
}

.form-group input:focus,
.form-group textarea:focus {
  outline: none;
  border-color: #0066cc;
  box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);
}

.contact-form button {
  width: 100%;
  padding: 1rem;
  background: #0066cc;
  color: white;
  border: none;
  border-radius: 4px;
  font-size: 1rem;
  font-weight: bold;
  cursor: pointer;
  transition: background 0.2s;
}

.contact-form button:hover {
  background: #0052a3;
}

.contact-form button:active {
  transform: translateY(1px);
}
</style>

Validation Styling

CSS pseudo-classes for form validation: Use :invalid selector for invalid inputs with red border, :valid selector for valid inputs with green border. Combine with :not(:placeholder-shown) to show validation only after user interaction. Use :focus state for active input styling with colored outlines.

Inline Form (Horizontal)

<form class="search-form">
  <input type="search" name="q" placeholder="Search..." required>
  <button type="submit">Search</button>
</form>

<style>
.search-form {
  display: flex;
  gap: 0.5rem;
  max-width: 500px;
}

.search-form input {
  flex: 1;
  padding: 0.75rem;
  border: 1px solid #ddd;
  border-radius: 4px;
}

.search-form button {
  padding: 0.75rem 1.5rem;
  background: #0066cc;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
</style>

14. Complete Form Examples

Registration Form

<form class="registration-form" action="/register" method="POST">
  <h2>Create Account</h2>

  <fieldset>
    <legend>Personal Information</legend>
    <div class="form-group">
      <label for="reg-fname">First Name:</label>
      <input type="text" id="reg-fname" name="first_name" required>
    </div>
    <div class="form-group">
      <label for="reg-email">Email:</label>
      <input type="email" id="reg-email" name="email" required>
    </div>
    
  </fieldset>

  <fieldset>
    <legend>Account Security</legend>
    <div class="form-group">
      <label for="reg-username">Username:</label>
      <input type="text" id="reg-username" name="username"
        pattern="[a-zA-Z0-9_]{3,16}" required>
    </div>
    <div class="form-group">
      <label for="reg-password">Password:</label>
      <input type="password" id="reg-password" name="password"
        minlength="8" required>
    </div>
    
  </fieldset>

  <fieldset>
    <legend>Preferences</legend>
    <label><input type="checkbox" name="interests" value="web"> Web Development</label>
    <label><input type="checkbox" name="interests" value="mobile"> Mobile Apps</label>
    <label><input type="checkbox" name="newsletter" value="1"> Subscribe to newsletter</label>
  </fieldset>

  <div class="form-group">
    <label>
      <input type="checkbox" name="terms" required>
      I accept the Terms and Conditions
    </label>
  </div>

  <button type="submit">Create Account</button>
</form>

Survey Form

<form class="survey-form" action="/survey" method="POST">
  <h2>Customer Satisfaction Survey</h2>

  <div class="form-group">
    <label for="customer-name">Name:</label>
    <input type="text" id="customer-name" name="name" required>
  </div>

  <fieldset>
    <legend>How satisfied are you with our service?</legend>
    <label><input type="radio" name="satisfaction" value="5" required> Very Satisfied</label>
    <label><input type="radio" name="satisfaction" value="3"> Neutral</label>
    <label><input type="radio" name="satisfaction" value="1"> Very Dissatisfied</label>
    
  </fieldset>

  <div class="form-group">
    <label for="visit-frequency">How often do you use our service?</label>
    <select id="visit-frequency" name="frequency" required>
      <option value="">-- Select --</option>
      <option value="daily">Daily</option>
      <option value="monthly">Monthly</option>
      
    </select>
  </div>

  <div class="form-group">
    <label for="comments">Additional Comments:</label>
    <textarea id="comments" name="comments" rows="5"></textarea>
  </div>

  <button type="submit">Submit Survey</button>
</form>

15. Practical Exercises

Exercise 2.6.1: Contact Form

Create a contact form with:

  1. Name (text, required)
  2. Email (email, required)
  3. Subject (select dropdown with 5 options)
  4. Message (textarea, required, 500 char max)
  5. Submit button
  6. Proper labels and styling

Exercise 2.6.2: Login Form

Build a login form with:

  1. Email input with validation
  2. Password input (min 8 characters)
  3. "Remember me" checkbox
  4. Submit button
  5. "Forgot password?" link
  6. Responsive styling

Exercise 2.6.3: Job Application Form

Create a comprehensive job application with:

  1. Personal info fieldset (name, email, phone)
  2. Experience level (radio buttons)
  3. Skills (multiple checkboxes)
  4. Resume upload (file input, PDF only)
  5. Cover letter (textarea)
  6. All fields with proper validation
  7. Professional styling

Exercise 2.6.4: Booking Form

Build a hotel booking form with:

  1. Check-in date (date input, min: today)
  2. Check-out date (date input)
  3. Number of guests (number input, 1-10)
  4. Room type (select dropdown)
  5. Special requests (textarea, optional)
  6. Total price calculator (JavaScript)
  7. Validation ensuring check-out > check-in

16. Knowledge Check

Question 1: What's the difference between GET and POST methods?

Show answer GET appends data to URL (visible, bookmarkable, for searches/filters). POST sends data in request body (hidden, for sensitive data, large payloads, and data modification).

Question 2: Why is the <label> element important?

Show answer Labels improve accessibility (screen readers announce them), increase click target (clicking label focuses input), and are required for good UX. Always associate labels with inputs using `for` attribute.

Question 3: How do you group related form fields?

Show answer Use `
` to group related fields and `` to provide a title. This creates visual grouping, semantic structure, and helps screen readers.

Question 4: What's the difference between radio buttons and checkboxes?

Show answer Radio buttons allow only ONE selection from a group (same `name` attribute). Checkboxes allow MULTIPLE selections. Use radio for exclusive choices, checkboxes for multiple choices.

Question 5: How do you validate an email input?

Show answer Use `type="email"` for built-in validation. Add `required` for mandatory field. Can also use `pattern` attribute for custom validation regex if needed.

Question 6: What's required for file upload forms?

Show answer 1) ``, 2) Form must use `method="POST"`, 3) Form must have `enctype="multipart/form-data"`. Use `accept` attribute to limit file types.

17. Common Mistakes

Missing Labels


<input type="text" placeholder="Name">

<label for="name">Name:</label>
<input type="text" id="name" name="name">

Wrong Input Type


<input type="text" name="email">

<input type="email" name="email" required>

No Name Attribute


<input type="text" id="username">

<input type="text" id="username" name="username">

Using Placeholder as Label


<input type="text" placeholder="Enter your name">

<label for="name">Name:</label>
<input type="text" id="name" name="name" placeholder="John Doe">

18. Key Takeaways

  • Always use <label> elements - Required for accessibility
  • Use appropriate input types - email, tel, number, date, etc.
  • Include name attribute - Required for form submission
  • Use GET for searches, POST for data - Choose method based on use case
  • Group with <fieldset> and <legend> - Better structure and accessibility
  • Validate with HTML5 attributes - required, pattern, min/max
  • Radio buttons for single choice - Checkboxes for multiple
  • File uploads need enctype - multipart/form-data
  • Style focus states clearly - Important for keyboard navigation
  • Test with keyboard only - Ensure tab order and accessibility

19. Further Resources

Official Documentation:

Accessibility:

Validation:


Next Steps

Excellent work! You now know how to build accessible, validated HTML forms.

In Lesson 2.7: Semantic HTML5, you'll learn the final piece of Phase 2 - using semantic HTML elements for better structure, accessibility, and SEO.