🛡️ Form Validation: The Bouncer at the Data Nightclub
Imagine you’re hosting the coolest party in town. But you can’t let just anyone in! You need a bouncer at the door who checks:
- Is this person on the guest list? (required fields)
- Are they wearing the right outfit? (pattern matching)
- Do they have a valid ID? (data validity)
Form validation is your bouncer. It checks every piece of information before it gets into your app!
🎯 What You’ll Learn
graph TD A["Form Validation"] --> B["Basics"] A --> C["Validity State"] A --> D["checkValidity"] A --> E["setCustomValidity"] A --> F["Pattern Validation"] A --> G["Required Validation"] A --> H["FormData API"]
1️⃣ Form Validation Basics
What is it?
Form validation is like a spell-checker for user input. Before someone submits a form, we check:
- Did they fill in the important stuff?
- Is the email actually an email?
- Is the phone number really a phone number?
Two Types of Validation
| Type | Where it happens | Example |
|---|---|---|
| Client-side | In the browser | Instant feedback! |
| Server-side | On the server | Double-checking |
Simple Example
<form id="partyForm">
<input
type="email"
required
placeholder="Your email">
<button type="submit">
Join Party!
</button>
</form>
What happens? If you try to submit without an email, the browser says “Nope! Fill this in first!”
Why Both Sides?
Think of it like airport security:
- 🏠 Client-side = Quick check at home before you leave
- ✈️ Server-side = Real security at the airport
Never trust only client-side! Sneaky people can bypass it.
2️⃣ Validity State
The Report Card for Inputs
Every input field has a secret report card called ValidityState. It tells you exactly what’s wrong!
The Validity Properties
const input = document
.querySelector('input');
// Get the report card
const validity = input.validity;
| Property | What it means |
|---|---|
valid |
Everything is perfect! ✅ |
valueMissing |
Required field is empty |
typeMismatch |
Wrong type (email, url) |
patternMismatch |
Doesn’t match pattern |
tooLong |
Too many characters |
tooShort |
Too few characters |
rangeOverflow |
Number too big |
rangeUnderflow |
Number too small |
stepMismatch |
Wrong step value |
customError |
You set a custom error |
Real Example
const email = document
.getElementById('email');
email.addEventListener('input', () => {
if (email.validity.typeMismatch) {
console.log("That's not an email!");
}
if (email.validity.valueMissing) {
console.log("Don't leave me empty!");
}
if (email.validity.valid) {
console.log("Perfect! 🎉");
}
});
Think of it like this: Each property is a different inspector checking one thing!
3️⃣ The checkValidity() Method
The Quick Yes/No Answer
Sometimes you just want to know: “Is this form okay or not?”
checkValidity() gives you a simple true or false.
On a Single Input
const nameInput = document
.getElementById('name');
if (nameInput.checkValidity()) {
console.log("Name is good! ✅");
} else {
console.log("Name has problems! ❌");
}
On the Whole Form
const form = document
.getElementById('myForm');
if (form.checkValidity()) {
console.log("All fields are valid!");
// Safe to submit!
} else {
console.log("Something is wrong!");
}
The Secret Trigger
When checkValidity() fails, it fires an invalid event:
nameInput.addEventListener(
'invalid',
(e) => {
console.log('Invalid!', e.target);
}
);
// This triggers the event!
nameInput.checkValidity();
Pro tip: Use this to show custom error messages!
4️⃣ The setCustomValidity() Method
Create Your Own Rules!
What if the built-in checks aren’t enough? Make your own!
The Magic Spell
const password = document
.getElementById('password');
password.addEventListener('input', () => {
if (password.value.length < 8) {
password.setCustomValidity(
"Password needs 8+ characters!"
);
} else {
// Clear the error!
password.setCustomValidity("");
}
});
⚠️ Super Important Rule!
You MUST clear the custom error when valid:
// Wrong - forgets to clear!
if (bad) {
input.setCustomValidity("Error!");
}
// Right - always clear when good!
if (bad) {
input.setCustomValidity("Error!");
} else {
input.setCustomValidity(""); // Clear!
}
Password Matching Example
const pass = document
.getElementById('password');
const confirm = document
.getElementById('confirm');
confirm.addEventListener('input', () => {
if (confirm.value !== pass.value) {
confirm.setCustomValidity(
"Passwords don't match!"
);
} else {
confirm.setCustomValidity("");
}
});
5️⃣ Pattern Validation
Regex: The Secret Code Checker
Patterns use regular expressions (regex). Think of them as a secret code that describes what’s allowed.
In HTML
<input
type="text"
pattern="[A-Za-z]{3,}"
title="3+ letters only"
placeholder="Your name">
| Pattern | What it allows |
|---|---|
[A-Za-z]+ |
Only letters |
[0-9]{5} |
Exactly 5 digits |
\d{3}-\d{4} |
123-4567 format |
[a-z]+@[a-z]+\.[a-z]+ |
Simple email |
Check Pattern in JavaScript
const phone = document
.getElementById('phone');
phone.addEventListener('blur', () => {
if (phone.validity.patternMismatch) {
phone.setCustomValidity(
"Use format: 555-1234"
);
} else {
phone.setCustomValidity("");
}
});
Phone Number Example
<input
type="tel"
pattern="\d{3}-\d{3}-\d{4}"
title="Format: 123-456-7890"
required>
Think of patterns like a lock: Only the right “key” (input format) opens it!
6️⃣ Required Validation
The “You MUST Fill This” Rule
The simplest validation. Just add required:
<input type="text" required>
<select required>
<option value="">Pick one</option>
<option value="a">Option A</option>
</select>
<textarea required></textarea>
Check if Required Field is Empty
const name = document
.getElementById('name');
if (name.validity.valueMissing) {
console.log("This field is required!");
}
Style Required Fields
/* Required fields get a star */
input:required {
border-left: 3px solid red;
}
/* Valid required = green */
input:required:valid {
border-left: 3px solid green;
}
/* Invalid = red glow */
input:invalid {
box-shadow: 0 0 3px red;
}
Required vs Optional
<!-- Must fill -->
<input required placeholder="Email *">
<!-- Optional -->
<input placeholder="Nickname (optional)">
7️⃣ FormData API
The Easy Way to Grab All Data
Instead of getting each input one by one, FormData collects everything at once!
The Basic Spell
const form = document
.getElementById('myForm');
form.addEventListener('submit', (e) => {
e.preventDefault();
const data = new FormData(form);
// Get one value
const name = data.get('name');
// Get all values with same name
const hobbies = data.getAll('hobby');
});
FormData Methods
| Method | What it does |
|---|---|
get(name) |
Get one value |
getAll(name) |
Get all values (checkboxes) |
set(name, value) |
Change a value |
append(name, value) |
Add new value |
delete(name) |
Remove a field |
has(name) |
Check if exists |
entries() |
Loop through all |
Loop Through Everything
const data = new FormData(form);
for (const [key, value] of data) {
console.log(`${key}: ${value}`);
}
Send to Server
const form = document
.getElementById('myForm');
form.addEventListener('submit',
async (e) => {
e.preventDefault();
if (!form.checkValidity()) {
return; // Stop if invalid!
}
const data = new FormData(form);
await fetch('/api/submit', {
method: 'POST',
body: data
});
});
Convert to Object
const data = new FormData(form);
const obj = Object.fromEntries(data);
console.log(obj);
// { name: "Sam", email: "sam@test.com" }
🎬 Putting It All Together
Here’s a complete example with everything we learned:
<form id="signupForm">
<input
id="email"
type="email"
name="email"
required
placeholder="Email *">
<input
id="password"
type="password"
name="password"
pattern=".{8,}"
required
placeholder="Password (8+ chars) *">
<input
id="confirmPass"
type="password"
required
placeholder="Confirm Password *">
<button type="submit">Sign Up</button>
</form>
const form = document
.getElementById('signupForm');
const password = document
.getElementById('password');
const confirm = document
.getElementById('confirmPass');
// Custom: passwords must match
confirm.addEventListener('input', () => {
if (confirm.value !== password.value) {
confirm.setCustomValidity(
"Passwords don't match!"
);
} else {
confirm.setCustomValidity("");
}
});
// Handle submit
form.addEventListener('submit', (e) => {
e.preventDefault();
if (!form.checkValidity()) {
form.reportValidity();
return;
}
const data = new FormData(form);
console.log("Submitting:",
Object.fromEntries(data)
);
});
🧠 Quick Memory Tricks
| Concept | Remember it as… |
|---|---|
validity |
The report card 📋 |
checkValidity() |
Quick pass/fail ✅❌ |
setCustomValidity() |
Your own rules 📝 |
pattern |
The secret code 🔐 |
required |
Must have! ⭐ |
FormData |
The collector 🎒 |
🎉 You Did It!
You now know how to:
- ✅ Validate forms on the client side
- ✅ Check validity state of any input
- ✅ Use
checkValidity()for yes/no answers - ✅ Create custom rules with
setCustomValidity() - ✅ Enforce patterns with regex
- ✅ Make fields required
- ✅ Collect all form data easily with FormData
Remember: Form validation is your friendly bouncer. It keeps bad data out and makes sure only the right guests get into your app! 🎊
