Lesson 2 of 107 min read

HTML Fundamentals

Share:WhatsAppLinkedIn

What you'll build

By the end of this lesson you will have a single HTML file that looks like a real web page, a personal profile page with a navigation bar, a short bio section, an image with a caption, a list of links, and a working contact form with client-side validation. No CSS yet, but the structure will be clean enough that adding CSS in the next lesson will be effortless.

Concepts

Document structure: doctype, head, body

Every HTML page starts with the same skeleton. The doctype tells the browser you are writing modern HTML5. The <head> holds metadata that the browser reads but does not display. The <body> holds everything the user sees.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Priya's Profile</title>
  <meta name="description" content="A short bio about Priya, a software developer.">
</head>
<body>
  <!-- Everything visible goes here -->
</body>
</html>

The charset tells the browser to expect UTF-8 text, which handles every Indian language script plus emoji. The viewport meta tag is what makes mobile browsers zoom to fit instead of showing a tiny desktop view, always include it.

Semantic elements

Semantic elements tell the browser (and screen readers and search engines) what a piece of content is, not just how it looks. Use them instead of stacking <div> tags for everything.

<body>
  <header>
    <nav>
      <a href="#about">About</a>
      <a href="#projects">Projects</a>
      <a href="#contact">Contact</a>
    </nav>
  </header>

  <main>
    <article id="about">
      <h1>Hi, I am Priya</h1>
      <p>I build web apps from Pune.</p>
    </article>

    <section id="projects">
      <h2>Projects</h2>
      <!-- project cards go here -->
    </section>
  </main>

  <aside>
    <p>Currently reading: Designing Data-Intensive Applications</p>
  </aside>

  <footer>
    <p>© 2026 Priya</p>
  </footer>
</body>

The rule of thumb: <header> is the top of a page or section, <nav> holds navigation links, <main> wraps the primary content (only one per page), <article> is self-contained content that makes sense on its own, <section> groups related content, <aside> is supplementary, and <footer> is the bottom of a page or section.

Links, lists, and images

These are the three building blocks of almost every page.

<!-- External link, opens in new tab (rel="noopener" is a security must) -->
<a href="https://github.com/priya" target="_blank" rel="noopener noreferrer">
  GitHub
</a>

<!-- Unordered list -->
<ul>
  <li>JavaScript</li>
  <li>Python</li>
  <li>PostgreSQL</li>
</ul>

<!-- Ordered list -->
<ol>
  <li>Write the HTML</li>
  <li>Add CSS</li>
  <li>Add JavaScript</li>
</ol>

<!-- Image: alt text is not optional -->
<figure>
  <img
    src="priya.jpg"
    alt="Priya smiling at her desk with a monitor showing code"
    width="400"
    height="400"
  >
  <figcaption>Working from home in Pune, 2026</figcaption>
</figure>

The alt attribute on images is read aloud by screen readers for visually impaired users. Write it as a description of what the image shows, not "photo" or "image". If the image is purely decorative, use alt="", that tells screen readers to skip it.

Forms with validation

HTML5 forms can enforce rules, required fields, email format, minimum length, without any JavaScript.

<form action="/submit" method="POST">
  <div>
    <label for="name">Your name</label>
    <input
      type="text"
      id="name"
      name="name"
      required
      minlength="2"
      placeholder="Arjun Sharma"
    >
  </div>

  <div>
    <label for="email">Email address</label>
    <input
      type="email"
      id="email"
      name="email"
      required
      placeholder="arjun@example.com"
    >
  </div>

  <div>
    <label for="message">Message</label>
    <textarea
      id="message"
      name="message"
      rows="5"
      required
      minlength="10"
    ></textarea>
  </div>

  <button type="submit">Send message</button>
</form>

The for attribute on <label> must match the id on the input it labels. This is an accessibility requirement, when a user clicks the label, the browser focuses the input. It also gives screen readers the connection they need to read "Your name: [input field]" instead of just "[input field]".

Accessibility basics

Accessibility (a11y) is not a feature you add later, it is a habit you build from the start. Three rules cover most of what you need right now.

<!-- 1. Always give images an alt attribute -->
<img src="chart.png" alt="Bar chart showing revenue grew 30% in Q1 2026">

<!-- 2. Always connect labels to inputs with matching for/id -->
<label for="search">Search courses</label>
<input type="search" id="search" name="q">

<!-- 3. Use heading levels in order (h1 > h2 > h3, never skip) -->
<h1>Web Development Path</h1>
  <h2>Lesson 2: HTML Fundamentals</h2>
    <h3>Forms with validation</h3>

A fourth habit: tab through your page with the keyboard. If you cannot reach every interactive element (links, buttons, inputs) by pressing Tab, something is wrong with your markup.

Hands-on

Let's build a complete profile page. Create a file called profile.html and paste this in:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Priya Menon, Developer</title>
  <meta name="description" content="Priya Menon is a web developer based in Pune, India.">
</head>
<body>

  <header>
    <nav>
      <a href="#about">About</a>
      <a href="#skills">Skills</a>
      <a href="#contact">Contact</a>
    </nav>
  </header>

  <main>

    <section id="about">
      <h1>Priya Menon</h1>
      <figure>
        <img
          src="https://via.placeholder.com/200"
          alt="Priya Menon, a web developer"
          width="200"
          height="200"
        >
        <figcaption>Based in Pune, Maharashtra</figcaption>
      </figure>
      <p>
        I am a self-taught web developer. I build clean, fast web applications
        and write about what I learn.
      </p>
    </section>

    <section id="skills">
      <h2>Skills</h2>
      <ul>
        <li>HTML and CSS</li>
        <li>JavaScript (React, Node)</li>
        <li>PostgreSQL</li>
        <li>Git and GitHub</li>
      </ul>
    </section>

    <section id="contact">
      <h2>Contact me</h2>
      <form action="#" method="POST">
        <div>
          <label for="name">Your name</label><br>
          <input
            type="text"
            id="name"
            name="name"
            required
            minlength="2"
            placeholder="Rahul Gupta"
          >
        </div>
        <br>
        <div>
          <label for="email">Email address</label><br>
          <input
            type="email"
            id="email"
            name="email"
            required
            placeholder="rahul@example.com"
          >
        </div>
        <br>
        <div>
          <label for="message">Your message</label><br>
          <textarea
            id="message"
            name="message"
            rows="5"
            cols="40"
            required
            minlength="10"
            placeholder="Hi Priya, I saw your project..."
          ></textarea>
        </div>
        <br>
        <button type="submit">Send</button>
      </form>
    </section>

  </main>

  <footer>
    <p>
      Find me on
      <a href="https://github.com/" target="_blank" rel="noopener noreferrer">GitHub</a>
      ·
      <a href="https://linkedin.com/" target="_blank" rel="noopener noreferrer">LinkedIn</a>
    </p>
    <p>© 2026 Priya Menon</p>
  </footer>

</body>
</html>

Open this file directly in your browser (drag it in, or right-click and open with browser). You will see unstyled but well-structured content. Try hitting Tab, you should be able to navigate every link and input field with just the keyboard.

Now try breaking the form validation: click Send without filling anything in. The browser will refuse and highlight the first empty required field. Change type="email" to type="text" and notice that any string is now accepted, the email format check was built into the input type, not the browser's generic required check.

Common pitfalls

  • Forgetting <!DOCTYPE html>. Without it, browsers drop into "quirks mode", a compatibility mode that renders pages slightly differently across browsers. Always start with the doctype.
  • Using headings for their size, not their meaning. Never use <h3> because you want smaller text. Use CSS for size. Headings convey document outline; jumbling the order breaks screen reader navigation.
  • Missing for/id connection on labels. Labels and inputs that are not linked do not activate each other on click, and screen readers cannot announce what the input is for. Always pair them.
  • Using <b> and <i> for visual styling. Prefer <strong> (important) and <em> (emphasis), they carry meaning. Use <b> and <i> only when you want visual bold/italic with no meaning attached.
  • Not setting width and height on images. Without these attributes, the browser does not reserve space for the image while it loads, causing layout shifts. Set them to the image's natural dimensions.

What to try next

  1. Add a <select> dropdown to the contact form asking how the person heard about you. Give it options like "GitHub", "Twitter", "Colleague". Make it required.
  2. Add an <input type="checkbox"> to the form for "I agree to be contacted". The submit button should be disabled until this is checked, you can do this with just HTML using the required attribute on the checkbox.
  3. Validate your HTML at validator.w3.org. Paste your file contents and read each warning. Fixing W3C warnings is one of the fastest ways to learn what "correct" HTML looks like.

Test Your Knowledge

Take a quick quiz on this lesson

Start Quiz →

Prefer watching over reading?

Subscribe for free.

Subscribe on YouTube