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 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
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 neededWrite 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 testsOptimize 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 analysisQuiz
1. What is the difference between GET and POST methods?
2. Why are labels important in forms?
3. What does the pattern attribute do?
4. What happens when a form field has no name attribute?
5. Which input type provides a date picker on mobile?
Flashcards
Question
What is the difference between explicit and implicit label association?
Click to reveal answer
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?
Click to reveal answer
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?
Click to reveal answer
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"?
Click to reveal answer
Answer
type="submit" triggers form submission when clicked. type="button" does nothing by default and requires JavaScript for behavior.
Question
What is HTML Forms?
Click to reveal answer
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