HTML & CSS · Lesson 2 of 5
Forms and Semantic HTML
Inputs, labels, validation and landmarks that make pages accessible.
- Beginner
- 15 min read
- 3 objectives
Before this lessonLesson 1: HTML Fundamentals
What you will learn
- Build an accessible form
- Use built-in validation
- Structure with header/nav/main/footer
Forms collect input, and semantic elements tell browsers, search engines and assistive technology what each part of a page is. Getting both right makes your site usable by everyone.
Structure with meaning
You could build every page from generic boxes, but browsers, search engines and assistive technology cannot tell a navigation menu from a footer if everything is a box. Semantic elements such as <header>, <nav>, <main>, <article> and <footer> describe the role of each region. They cost nothing and make pages more accessible, easier to maintain and better for search.
Semantic layout
<body>
<header>
<nav><a href="/">Home</a> <a href="/blog/">Blog</a></nav>
</header>
<main>
<article>
<h1>Post title</h1>
<p>Content...</p>
</article>
<aside>Related links</aside>
</main>
<footer>© 2026</footer>
</body>Prefer these over a sea of <div> elements. Screen-reader users can jump straight to main or nav, and search engines understand the page better. Use <div> and <span> only when nothing more meaningful fits.
A form
<form action="/signup" method="post">
<label for="email">Email</label>
<input id="email" name="email" type="email" required autocomplete="email">
<label for="pw">Password</label>
<input id="pw" name="password" type="password" minlength="8" required>
<label for="plan">Plan</label>
<select id="plan" name="plan">
<option value="free">Free</option>
<option value="pro">Pro</option>
</select>
<fieldset>
<legend>Contact by</legend>
<label><input type="radio" name="contact" value="email" checked> Email</label>
<label><input type="radio" name="contact" value="phone"> Phone</label>
</fieldset>
<label><input type="checkbox" name="terms" required> I agree to the terms</label>
<textarea name="notes" rows="3" placeholder="Anything else?"></textarea>
<button type="submit">Create account</button>
</form>Labels matter
Every input needs a <label> linked by for/id (or by wrapping the input). Clicking the label focuses the field, and screen readers announce it. Placeholder text is not a substitute, since it disappears as soon as you type.
Input types and built-in validation
type:email,url,tel,number,date,password,search,file. Mobile keyboards adapt to the type.- Validation attributes:
required,min,max,minlength,maxlength,pattern. - The
nameattribute is the key sent to the server; an input without one is not submitted.
Buttons
Inside a form a <button> submits by default. Use type="button" for buttons that should not submit. Use a <button> for actions and an <a> for navigation.
Accessibility quick wins
- Everything usable with a keyboard: tab through your page.
- Sufficient color contrast (aim for 4.5:1 for body text).
- Meaningful link text: "Read the pricing guide", not "click here".
A whole page laid out semantically
<body>
<header>
<h1>Bean Counter Coffee</h1>
<nav>
<a href="/menu">Menu</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
</header>
<main>
<article>
<h2>Our new espresso</h2>
<p>Rich, chocolatey and roasted this week.</p>
</article>
<aside>
<h2>Opening hours</h2>
<p>Mon-Fri 7am to 5pm</p>
</aside>
</main>
<footer><p>© 2026 Bean Counter</p></footer>
</body>How a form works
A form collects what a user types and sends it somewhere. Every field needs a name (the label the data is sent under) and a visible <label>. Clicking a label focuses its field, which also helps screen readers and makes small targets easier to hit on a phone.
<form action="/subscribe" method="post">
<label for="email">Email</label>
<input id="email" name="email" type="email" required>
<label for="plan">Plan</label>
<select id="plan" name="plan">
<option value="free">Free</option>
<option value="pro">Pro</option>
</select>
<label>
<input type="checkbox" name="terms" required>
I agree to the terms
</label>
<button type="submit">Subscribe</button>
</form>for="email"on the label matchesid="email"on the input.type="email"makes phones show an email keyboard and the browser check the format.requiredblocks submitting an empty field, with no JavaScript needed.method="post"sends the data in the request body;getputs it in the URL (good for searches, wrong for passwords).
Choosing the right input type
<input type="text"> <!-- free text -->
<input type="number" min="1" max="10">
<input type="date">
<input type="password">
<input type="tel">
<input type="url">
<input type="range" min="0" max="100">
<textarea name="message" rows="4"></textarea>Key takeaways
- Use semantic elements (
header,nav,main,article,footer) instead of anonymous boxes. - Every form field needs a
nameand a properly linked<label>. - Pick the input
typethat matches the data; the browser then helps for free. - Always re-validate form data on the server.
// Write your solution here
