HTML Forms & Input Validation
HTML5 provides extensive form capabilities including validation, many input types, and the FormData API. Understanding forms is fundamental to web development.
Form Structure
<form action="/submit" method="post" id="signup-form" novalidate>
<!-- novalidate disables browser's native validation UI — useful when custom validation -->
<fieldset>
<legend>Personal Information</legend>
<!-- Proper label association — click label focuses input -->
<label for="name">Full Name</label>
<input type="text" id="name" name="name" required autocomplete="name">
<label for="email">Email Address</label>
<input type="email" id="email" name="email" required autocomplete="email">
</fieldset>
<!-- Submit button inside form is associated automatically -->
<button type="submit">Create Account</button>
<!-- Reset clears all fields to their default values -->
<button type="reset">Clear Form</button>
<!-- Button outside form can be linked via form attribute -->
</form>
<button form="signup-form" type="submit">Submit from outside</button>Input Types
<!-- Text inputs -->
<input type="text" placeholder="Enter text">
<input type="email" autocomplete="email">
<input type="password" autocomplete="current-password" minlength="8">
<input type="tel" autocomplete="tel" pattern="[0-9]{10}">
<input type="url">
<input type="search"> <!-- shows clear button on some browsers -->
<!-- Numbers -->
<input type="number" min="0" max="100" step="5">
<input type="range" min="0" max="10" value="5"> <!-- slider -->
<!-- Dates & Times -->
<input type="date" min="2024-01-01" max="2024-12-31">
<input type="time" step="900"> <!-- step in seconds: 900 = 15min increments -->
<input type="datetime-local">
<input type="month">
<input type="week">
<!-- Pickers -->
<input type="color" value="#0070f3">
<input type="file" accept="image/*,.pdf" multiple>
<!-- Selection -->
<input type="checkbox" id="agree" name="agree" value="yes" checked>
<input type="radio" name="size" value="sm"> Small
<input type="radio" name="size" value="lg"> Large
<!-- Hidden -->
<input type="hidden" name="csrf_token" value="abc123">
<input type="hidden" name="user_id" value="42">Validation Attributes
<!-- Built-in validation (works without JavaScript) -->
<input type="email" required>
<!-- required: must not be empty -->
<!-- type="email": must match email format -->
<input type="text" minlength="2" maxlength="100" required>
<!-- minlength/maxlength: character count constraints -->
<input type="number" min="1" max="99" step="1">
<!-- min/max: value range; step: increments -->
<input type="text" pattern="[A-Za-z]{3,}" title="At least 3 letters only">
<!-- pattern: regex validation; title: shown in error tooltip -->
<input type="url" required>
<!-- Textarea -->
<textarea maxlength="500" required></textarea>
<!-- Custom validation with JavaScript -->
<input type="text" id="username">
<script>
document.getElementById('username').addEventListener('input', (e) => {
const el = e.target;
if (!/^[a-z0-9_]+$/.test(el.value)) {
el.setCustomValidity('Only lowercase letters, numbers, and underscores');
} else {
el.setCustomValidity(''); // clear error
}
});
</script>Select, Datalist & Textarea
<!-- Select dropdown -->
<select name="country" required>
<option value="" disabled selected>Choose a country</option>
<optgroup label="Europe">
<option value="uk">United Kingdom</option>
<option value="de">Germany</option>
</optgroup>
<optgroup label="Americas">
<option value="us">United States</option>
</optgroup>
</select>
<!-- Multiple select -->
<select name="skills" multiple size="4">
<option value="js">JavaScript</option>
<option value="ts" selected>TypeScript</option>
<option value="py">Python</option>
</select>
<!-- Datalist — autocomplete suggestions for text input -->
<input type="text" list="frameworks" name="framework">
<datalist id="frameworks">
<option value="React">
<option value="Vue">
<option value="Angular">
<option value="Svelte">
</datalist>
<!-- Textarea -->
<textarea name="message" rows="4" cols="50"
placeholder="Your message..." maxlength="1000"></textarea>FormData API
// Intercept form submission and send via fetch
document.getElementById('signup-form').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
// Read values
const name = formData.get('name'); // single value
const skills = formData.getAll('skills'); // multiple values (checkboxes)
// Modify before sending
formData.set('email', formData.get('email').toLowerCase());
formData.append('timestamp', Date.now().toString());
// Send as JSON
const data = Object.fromEntries(formData.entries());
const res = await fetch('/api/signup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
// Send as multipart/form-data (for file uploads)
const res2 = await fetch('/api/upload', {
method: 'POST',
body: formData, // don't set Content-Type — browser sets boundary automatically
});
});Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free