Stop 03 · HTML, CSS & JavaScript EssentialsTopics · 2/11

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.

The mascot hands a form to a desk clerk while an officer behind glass rechecks it with a magnifier.

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

Typing
HTML rules
JS check
Server
Database

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

js
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

~30 min

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

  1. 1Build a form with HTML5 validation attributes (`required`, `pattern`, `type="email"`).
  2. 2Practice handling form submission in JavaScript with `preventDefault()`.
  3. 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.

Download
InsideEdge