Forms & Validation
Part of the Full Stack Developer Roadmap
In short
Every signup, checkout and contact page is a form. A full stack form checks input twice: once in the browser for speed, once on the server for safety.
Collecting and validating user input — from HTML5's built-in validation attributes to the client-side and server-side checks a real full-stack form needs at both ends.

Think of it like this
The passport office's two checks
At the passport office, the front desk glances at your form and sends you back if a field is empty. Inside, an officer checks every document again properly. The quick desk check saves time. The officer's check is the one that actually counts.
Watch it happen
One form value, five gates
1/5The user types a phone number: 98765 4321. One digit short, with a space in the middle.
The big ideas
What you need to know
Browser checks are for speed
required, type="email", min, max and pattern give instant feedback without a round trip to the server.
Server checks are for safety
Anyone can switch off JavaScript or send a raw request. The server must never trust what the form says.
Same rules, both ends
Write the rules once in a shared schema (Zod is popular) and run it in React and Express, so they never disagree.
Show errors next to fields
Send back which field failed and why, then show the message under that input, not as one vague alert.
See it in code
Walk through the code
1// Browser: let HTML do the first check, then send2form.addEventListener("submit", async (e) => {3 e.preventDefault();4 if (!form.checkValidity()) return form.reportValidity();5 const body = Object.fromEntries(new FormData(form));6 const res = await fetch("/api/signup", { method: "POST",7 headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) });8 if (!res.ok) errorBox.textContent = (await res.json()).error;9});10 11// Server: check again, the browser can be bypassed12app.post("/api/signup", (req, res) => {13 const { phone } = req.body;14 if (!/^[6-9][0-9]{9}$/.test(phone ?? "")) return res.status(400).json({ error: "Enter a 10-digit mobile number" });15 // ...save the user, then res.status(201).json(user)16});1/4Stop the normal page reload, then let the browser run the HTML rules and show its bubbles.
The browser check makes the form feel fast. The server check is the one an attacker can't skip.
Save yourself the pain
Common mistakes
Oops
Relying on required and pattern attributes alone, because 'the form won't submit without them'.
Do this instead
Those only stop the browser form. Your API gets hit directly too, so validate every field on the server.
Oops
Returning a generic 'Something went wrong' for every bad input.
Do this instead
Return a 400 with the field name and a clear reason, so the frontend can show it in the right place.
Your mission
Break your own form
Quick check
Your form has required on the email field. A user sends a POST with no email using Postman. What stops it?
Go deeper
- 1Build a form with HTML5 validation attributes (`required`, `pattern`, `type="email"`).
- 2Practice handling form submission in JavaScript with `preventDefault()`.
- 3Remember: client-side validation is a UX nicety, server-side validation is the actual security boundary.
More topics at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.