Learn / Programming / HTML & CSS / Forms and Semantic HTML

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>&copy; 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 name attribute 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>&copy; 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 matches id="email" on the input.
  • type="email" makes phones show an email keyboard and the browser check the format.
  • required blocks submitting an empty field, with no JavaScript needed.
  • method="post" sends the data in the request body; get puts 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 name and a properly linked <label>.
  • Pick the input type that matches the data; the browser then helps for free.
  • Always re-validate form data on the server.
// Write your solution here
Up next · Lesson 3CSS BasicsSelectors, the cascade, the box model, colors and typography.