Skip to content
beginnerPhase 30 · HTML

HTML Forms

Build forms with input types, validation attributes, and form submission handling.

1h
0 problems
Topic Progress0%

Form Basics

Forms are how users send data to a server. Every login page, search bar, and checkout flow uses forms.

Basic Form Structure

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

The form Element

<form action="/submit" method="POST" enctype="multipart/form-data">
    <!-- form fields go here -->
</form>
Attribute Purpose Values
action URL to send data to Any URL
method HTTP method GET, POST
enctype Encoding type application/x-www-form-urlencoded, multipart/form-data, text/plain
target Where to show response _self, _blank, _parent, _top
novalidate Disable validation novalidate

GET vs POST

GET (default):
  - Data in URL: /search?query=hello&lang=en
  - Visible in address bar
  - Bookmarkable
  - For search, filtering, non-sensitive data

POST:
  - Data in request body
  - Not visible in URL
  - Not bookmarkable
  - For login, payments, file uploads

When to Use Each

Scenario Method
Search form GET
Login form POST
File upload POST
Newsletter signup POST
Filter/sort products GET

Labels and Accessibility

Labels are critical for accessibility. They connect form fields to descriptive text.

Why Labels Matter

  • Accessibility: Screen readers announce field purpose
  • Click target: Users can click the label to focus the input
  • Required for WCAG compliance

Explicit Association (Recommended)

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

<!-- Clicking the label focuses the input -->

Implicit Association

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

<!-- Works but less flexible for styling -->

Grouped Labels (Fieldset + Legend)

<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">
    
    <label for="zip">ZIP Code</label>
    <input type="text" id="zip" name="zip">
</fieldset>

Accessible Error Messages

<label for="password">Password</label>
<input type="password" id="password" name="password"
       aria-describedby="password-error" aria-invalid="false">
<span id="password-error" class="error" role="alert"></span>

<!-- aria-describedby links the error message to the input -->

Best Practices

  • Always use labels with every form field
  • One label per field (never skip labels)
  • Use fieldset/legend for grouped controls
  • Place labels above or beside inputs (not below)
  • Make labels clickable (increases tap target)

Input Types

HTML5 introduced many input types that provide built-in validation and appropriate mobile keyboards.

Text Inputs

<!-- Plain text -->
<input type="text" name="name" placeholder="John Doe">

<!-- Password (hidden) -->
<input type="password" name="password">

<!-- Email (validated) -->
<input type="email" name="email">

<!-- URL (validated) -->
<input type="url" name="website">

<!-- Phone (mobile keyboard) -->
<input type="tel" name="phone">

<!-- Search (search keyboard on mobile) -->
<input type="search" name="query">

Number Inputs

<!-- Number (spinner controls) -->
<input type="number" name="age" min="0" max="150" step="1">

<!-- Range (slider) -->
<input type="range" name="volume" min="0" max="100" step="5">

<!-- Display value -->
<output id="volume-output">50</output>

Date Inputs

<input type="date" name="birthday">
<input type="datetime-local" name="appointment">
<input type="time" name="meeting-time">
<input type="week" name="week-number">
<input type="month" name="birth-month">

Choice Inputs

<!-- Checkbox (multiple selections) -->
<input type="checkbox" name="hobby" value="reading"> Reading
<input type="checkbox" name="hobby" value="gaming"> Gaming

<!-- Radio (single selection) -->
<input type="radio" name="color" value="red"> Red
<input type="radio" name="color" value="blue"> Blue
<input type="radio" name="color" value="green"> Green

<!-- Select dropdown -->
<select name="country">
    <option value="">Select a country</option>
    <option value="us">United States</option>
    <option value="uk">United Kingdom</option>
</select>

Specialized Inputs

<!-- File upload -->
<input type="file" name="avatar" accept="image/*">
<input type="file" name="documents" accept=".pdf,.doc" multiple>

<!-- Color picker -->
<input type="color" name="theme-color" value="#ff0000">

<!-- Hidden field -->
<input type="hidden" name="csrf-token" value="abc123">

Input Type Summary

Type Mobile Keyboard Built-in Validation
text Default None
email Email Email format
url URL URL format
tel Phone None
number Number Number range
date Date picker Date format
time Time picker Time format
search Search None
password Password None

HTML5 Validation Attributes

HTML5 provides built-in validation without JavaScript.

Required Fields

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

Length Constraints

<input type="text" name="username" minlength="3" maxlength="20">
<input type="password" name="password" minlength="8">

Number Constraints

<input type="number" name="age" min="18" max="120">
<input type="number" name="quantity" min="1" step="1">
<input type="range" name="rating" min="1" max="5" step="1">

Pattern Matching (Regex)

<!-- Phone: (123) 456-7890 -->
<input type="tel" name="phone" 
       pattern="\(\d{3}\) \d{3}-\d{4}">

<!-- ZIP code: 12345 or 12345-6789 -->
<input type="text" name="zip" 
       pattern="\d{5}(-\d{4})?">

<!-- Username: 3-16 chars, letters and underscores -->
<input type="text" name="username" 
       pattern="[A-Za-z_]{3,16}">

Custom Validation Messages

const input = document.querySelector('input[name="email"]');

input.addEventListener('invalid', (e) => {
    if (input.validity.valueMissing) {
        input.setCustomValidity('Please enter your email');
    } else if (input.validity.typeMismatch) {
        input.setCustomValidity('Please enter a valid email');
    } else {
        input.setCustomValidity('');
    }
});

Validation API

const input = document.querySelector('input');

// Check validity
console.log(input.validity.valid);          // true/false
console.log(input.validity.valueMissing);    // required but empty
console.log(input.validity.typeMismatch);    // wrong type
console.log(input.validity.tooShort);        // below minlength
console.log(input.validity.rangeUnderflow);  // below min
console.log(input.validity.patternMismatch); // doesn't match pattern

// Trigger validation
input.reportValidity();  // Shows browser's validation UI
input.checkValidity();   // Returns true/false without showing UI

Form Layout Elements

HTML provides elements for structuring and organizing forms.

textarea (Multi-line Text)

<label for="bio">Bio</label>
<textarea id="bio" name="bio" 
          rows="4" cols="50"
          maxlength="500"
          placeholder="Tell us about yourself"></textarea>

Select (Dropdown)

<select name="language" required>
    <option value="">Choose a language</option>
    <optgroup label="Programming">
        <option value="js">JavaScript</option>
        <option value="py">Python</option>
    </optgroup>
    <optgroup label="Web">
        <option value="html">HTML</option>
        <option value="css">CSS</option>
    </optgroup>
</select>

datalist (Autocomplete)

<label for="browser">Browser</label>
<input type="text" id="browser" name="browser" list="browsers">
<datalist id="browsers">
    <option value="Chrome">
    <option value="Firefox">
    <option value="Safari">
    <option value="Edge">
</datalist>

<!-- User can type custom value or select from list -->

button Element

<!-- Submit (default) -->
<button type="submit">Submit</button>

<!-- Button (no default behavior) -->
<button type="button" onclick="doSomething()">Click Me</button>

<!-- Reset (clears form) -->
<button type="reset">Reset Form</button>

output Element

<form oninput="result.value = parseInt(a.value) + parseInt(b.value)">
    <input type="number" id="a" value="0">
    +
    <input type="number" id="b" value="0">
    = <output name="result" for="a b">0</output>
</form>

progress and meter

<!-- Progress bar -->
<progress value="70" max="100">70%</progress>

<!-- Meter (gauge) -->
<meter value="0.7" min="0" max="1">70%</meter>
<meter value="0.2" min="0" low="0.3" high="0.7" max="1">20%</meter>

Form Submission

Understanding how forms submit data is crucial for building functional forms.

How Data is Sent

Form fields are sent as key=value pairs:

GET /search?query=hello&lang=en
POST body: query=hello&lang=en

Name attribute = key
Value attribute = value

The name Attribute

<!-- name is REQUIRED for data to be sent -->
<input type="text" name="username">  <!-- Sent: username=john -->
<input type="text">                   <!-- NOT sent (no name) -->

<!-- Multiple checkboxes with same name -->
<input type="checkbox" name="hobby" value="reading"> Reading
<input type="checkbox" name="hobby" value="gaming"> Gaming
<!-- Sent: hobby=reading&hobby=gaming -->

Form Submission Flow

1. User clicks submit button
2. Browser validates all fields (if novalidate not set)
3. If valid, browser collects form data
4. Browser sends HTTP request to action URL
5. Server processes the data
6. Server sends response

Preventing Default Submission

<form id="myForm">
    <input type="email" name="email" required>
    <button type="submit">Submit</button>
</form>

<script>
document.getElementById('myForm').addEventListener('submit', (e) => {
    e.preventDefault(); // Stop form from submitting
    
    // Handle with JavaScript instead
    const formData = new FormData(e.target);
    console.log(Object.fromEntries(formData));
});
</script>

FormData API

const form = document.querySelector('form');
const formData = new FormData(form);

// Get values
formData.get('username');        // Single value
formData.getAll('hobby');        // All values for array fields

// Iterate
for (const [key, value] of formData) {
    console.log(key, value);
}

// Convert to object
const data = Object.fromEntries(formData);

// Send with fetch
fetch('/api/submit', {
    method: 'POST',
    body: formData
});

Practice Problems

0/3solved
Build HTML Forms Component

Create a reusable React component implementing HTML Forms. Include proper state management and accessibility.

Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where needed
HTML Forms Testing

Write unit and integration tests for HTML Forms using React Testing Library.

Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility tests
HTML Forms Performance

Optimize HTML Forms for performance. Consider memoization, code splitting, and bundle size.

Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysis

Quiz

1. What is the difference between GET and POST methods?

Question 1 options

2. Why are labels important in forms?

Question 2 options

3. What does the pattern attribute do?

Question 3 options

4. What happens when a form field has no name attribute?

Question 4 options

5. Which input type provides a date picker on mobile?

Question 5 options

Flashcards

Question

What is the difference between explicit and implicit label association?

Answer

Explicit uses for="id" to link to input's id. Implicit wraps the input inside the label element. Explicit is preferred for better flexibility and styling.

Question

When should you use fieldset and legend?

Answer

Use them to group related form controls (like radio buttons or address fields). Legend provides the group's accessible label.

Question

What is the purpose of the novalidate attribute?

Answer

It disables the browser's built-in validation when the form is submitted, allowing you to handle validation with JavaScript instead.

Question

What is the difference between type="submit" and type="button"?

Answer

type="submit" triggers form submission when clicked. type="button" does nothing by default and requires JavaScript for behavior.

Question

What is HTML Forms?

Answer

HTML Forms is a key concept in frontend development.

Revision Notes

Key Takeaways

  • 1.Always use labels with form fields for accessibility
  • 2.Use GET for search/filter forms, POST for data submission
  • 3.HTML5 validation attributes reduce JavaScript needed
  • 4.The name attribute is required for fields to be submitted
  • 5.Use fieldset and legend to group related controls
  • 6.FormData API makes form data handling easy in JavaScript

Interview Tips

  • Know the difference between GET and POST and when to use each
  • Understand HTML5 validation attributes (required, pattern, min/max)
  • Be able to explain accessible form practices (labels, fieldset, aria-describedby)
  • Know how FormData API works with fetch for AJAX form submission

Cheat Sheet

HTML Forms Cheat Sheet

<form action="/url" method="POST">
  <label for="name">Name</label>
  <input type="text" id="name" name="name" required>
  
  <button type="submit">Submit</button>
</form>

Input Types: text, email, url, tel, number, password, date, time, search, file, color, range, checkbox, radio

Validation Attributes: required, pattern, min, max, minlength, maxlength, step

Key Elements: form, input, label, select, textarea, button, fieldset, legend, datalist