HTML course
html programming language icon

HTML Exercises: 22 Practice Problems with Solutions

Good HTML is about meaning, not appearance. These problems cover document structure, semantic landmarks, text and links, media, accessible tables and forms, ARIA basics, metadata and structured data.

Paste your markup into the editor below and run it to see the rendered page. Compare your structure to the solution: both may look the same while only one is semantic.

Run your answer here

Type your solution, press Run, and use the Input box when a problem asks you to read from standard input.

HTML Compiler
CSS (optional)
Output
Code runs in a sandboxed preview inside your browser — your code is saved locally for next time.

How to practise so it actually sticks

Attempt the problem before opening the solution, even if your first version is clumsy. A working ugly answer teaches more than a beautiful one you read. When you get stuck for more than five minutes, read the hint — not the solution — and try again.

After you pass, open the solution and ask what is different about it. Shorter? Fewer variables? A built-in you did not know? That comparison is where most of the growth happens. Then change the problem slightly: sort the other direction, handle an empty input, read a value instead of hard-coding it.

Aim for three to five problems a day rather than thirty in one sitting. Spacing practice over days is what moves syntax from "I can look it up" to "my fingers know it".

The exercises

Showing 22 of 22 exercises.

  1. BeginnerDocument structure

    1. A valid page skeleton

    Write a complete HTML5 page with a doctype, language attribute, charset, viewport, title and one heading.

    Hint: Every modern page starts with <!DOCTYPE html>.

    <!DOCTYPE html>
    <html>
    </html>
    Show solution
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>My first page</title>
      </head>
      <body>
        <h1>Hello, HTML</h1>
      </body>
    </html>
  2. BeginnerDocument structure

    2. Headings in order

    Write one h1 and two h2 sections beneath it, each with a paragraph.

    Hint: Only one h1 per page; do not skip levels.

    <h1></h1>
    Show solution
    <h1>Learning HTML</h1>
    <h2>Why structure matters</h2>
    <p>Screen readers and search engines both rely on heading order.</p>
    <h2>What comes next</h2>
    <p>Once structure is right, styling is easy.</p>
  3. IntermediateDocument structure

    3. Semantic page regions

    Lay out a page using header, nav, main, aside and footer instead of generic divs.

    Hint: Each landmark should appear once, except nav.

    <div class="page"></div>
    Show solution
    <header>
      <h1>Play with Coding</h1>
      <nav>
        <a href="/languages">Courses</a>
        <a href="/compiler">Compiler</a>
      </nav>
    </header>
    <main>
      <h2>Today's lesson</h2>
      <p>Semantic elements describe meaning, not appearance.</p>
    </main>
    <aside>
      <h2>Tip</h2>
      <p>Use one main element per page.</p>
    </aside>
    <footer>
      <p>&copy; 2026 Play with Coding</p>
    </footer>
  4. BeginnerText & links

    4. Emphasis and quotations

    Write a paragraph using strong, em, a blockquote with cite, and inline code.

    Hint: strong means importance, em means stress — not bold and italic.

    <p></p>
    Show solution
    <p>You <strong>must</strong> close every tag, and indentation is <em>only</em> for humans.</p>
    <blockquote cite="https://developer.mozilla.org/">
      <p>HTML is the most basic building block of the web.</p>
    </blockquote>
    <p>The element for inline code is <code>&lt;code&gt;</code>.</p>
  5. BeginnerText & links

    5. Links that behave well

    Write an internal link, an external link that opens in a new tab safely, an email link and an in-page anchor.

    Hint: External new-tab links need rel="noopener noreferrer".

    <ul>
    </ul>
    Show solution
    <ul>
      <li><a href="/languages">Browse courses</a></li>
      <li><a href="https://developer.mozilla.org" target="_blank" rel="noopener noreferrer">MDN docs</a></li>
      <li><a href="mailto:hello@example.com">Email us</a></li>
      <li><a href="#faq">Jump to the FAQ</a></li>
    </ul>
    <h2 id="faq">FAQ</h2>
  6. BeginnerText & links

    6. Three kinds of list

    Write an unordered list, an ordered list starting at 3, and a description list of two terms.

    Hint: dl pairs dt with dd.

    Show solution
    <ul>
      <li>HTML</li>
      <li>CSS</li>
    </ul>
    <ol start="3">
      <li>Third step</li>
      <li>Fourth step</li>
    </ol>
    <dl>
      <dt>Element</dt>
      <dd>A tag plus its content.</dd>
      <dt>Attribute</dt>
      <dd>Extra information on an element.</dd>
    </dl>
  7. IntermediateMedia

    7. Responsive images with alt text

    Add an image with descriptive alt text, explicit width and height, lazy loading, and a figure caption.

    Hint: Width and height prevent layout shift while the image loads.

    <figure>
    </figure>
    Show solution
    <figure>
      <img
        src="/assets/hero.jpg"
        alt="A student writing Python code on a laptop"
        width="1200"
        height="630"
        loading="lazy"
      />
      <figcaption>Practising in the browser compiler.</figcaption>
    </figure>
  8. AdvancedMedia

    8. Serve different image sizes

    Use picture with two source elements so mobile gets a smaller image, plus an img fallback.

    Hint: media attributes on source pick the candidate.

    <picture>
    </picture>
    Show solution
    <picture>
      <source media="(min-width: 900px)" srcset="/hero-large.jpg" />
      <source media="(min-width: 500px)" srcset="/hero-medium.jpg" />
      <img src="/hero-small.jpg" alt="Course hero artwork" width="600" height="400" />
    </picture>
  9. IntermediateMedia

    9. Embed audio and video

    Embed a video with controls, a poster image and a captions track, plus an audio element.

    Hint: track kind="captions" makes video accessible.

    Show solution
    <video controls poster="/poster.jpg" width="640" height="360">
      <source src="/lesson.mp4" type="video/mp4" />
      <track kind="captions" src="/lesson.vtt" srclang="en" label="English" default />
      Your browser does not support video.
    </video>
    <audio controls src="/intro.mp3"></audio>
  10. IntermediateTables

    10. An accessible data table

    Build a table with a caption, thead, tbody, tfoot and scoped header cells.

    Hint: scope="col" ties a header to its column.

    <table>
    </table>
    Show solution
    <table>
      <caption>Quiz results</caption>
      <thead>
        <tr>
          <th scope="col">Student</th>
          <th scope="col">Score</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <th scope="row">Ada</th>
          <td>91</td>
        </tr>
        <tr>
          <th scope="row">Ben</th>
          <td>74</td>
        </tr>
      </tbody>
      <tfoot>
        <tr>
          <th scope="row">Average</th>
          <td>82.5</td>
        </tr>
      </tfoot>
    </table>
  11. AdvancedTables

    11. Spanning cells

    Create a table where one header spans two columns and one cell spans two rows.

    Hint: colspan and rowspan take a number.

    <table>
    </table>
    Show solution
    <table>
      <tr>
        <th scope="col">Week</th>
        <th scope="col" colspan="2">Topics</th>
      </tr>
      <tr>
        <td rowspan="2">1</td>
        <td>HTML</td>
        <td>Structure</td>
      </tr>
      <tr>
        <td>CSS</td>
        <td>Styling</td>
      </tr>
    </table>
  12. BeginnerForms

    12. A labelled form

    Build a form with a name field, an email field and a submit button, every input properly labelled.

    Hint: Match the label's for attribute to the input's id.

    <form>
    </form>
    Show solution
    <form action="/subscribe" method="post">
      <label for="name">Name</label>
      <input id="name" name="name" type="text" required />
    
      <label for="email">Email</label>
      <input id="email" name="email" type="email" required autocomplete="email" />
    
      <button type="submit">Subscribe</button>
    </form>
  13. IntermediateForms

    13. Pick the right input type

    Add fields for a date, a number between 1 and 10, a password, a phone number and a colour.

    Hint: The right type gives mobile users the right keyboard.

    <form>
    </form>
    Show solution
    <form>
      <label for="d">Date</label>
      <input id="d" type="date" name="date" />
    
      <label for="n">Rating</label>
      <input id="n" type="number" name="rating" min="1" max="10" step="1" />
    
      <label for="p">Password</label>
      <input id="p" type="password" name="password" minlength="8" autocomplete="new-password" />
    
      <label for="t">Phone</label>
      <input id="t" type="tel" name="phone" inputmode="tel" />
    
      <label for="c">Favourite colour</label>
      <input id="c" type="color" name="colour" />
    </form>
  14. IntermediateForms

    14. Group related controls

    Group three radio buttons in a fieldset with a legend, and add a select with an optgroup.

    Hint: Radios share the same name attribute.

    <form>
    </form>
    Show solution
    <form>
      <fieldset>
        <legend>Experience level</legend>
        <label><input type="radio" name="level" value="beginner" checked /> Beginner</label>
        <label><input type="radio" name="level" value="intermediate" /> Intermediate</label>
        <label><input type="radio" name="level" value="advanced" /> Advanced</label>
      </fieldset>
    
      <label for="lang">Language</label>
      <select id="lang" name="lang">
        <optgroup label="Scripting">
          <option value="python">Python</option>
          <option value="javascript">JavaScript</option>
        </optgroup>
        <optgroup label="Systems">
          <option value="c">C</option>
          <option value="rust">Rust</option>
        </optgroup>
      </select>
    </form>
  15. AdvancedForms

    15. Built-in validation

    Require a username of 3 to 16 characters matching a pattern, and show a helpful title.

    Hint: pattern takes a regular expression without slashes.

    <form>
    </form>
    Show solution
    <form>
      <label for="u">Username</label>
      <input
        id="u"
        name="username"
        type="text"
        required
        minlength="3"
        maxlength="16"
        pattern="[a-z0-9_]+"
        title="Lowercase letters, numbers and underscores only"
      />
      <button type="submit">Create account</button>
    </form>
  16. AdvancedAccessibility

    16. Accessible interactive markup

    Add a skip link, an icon-only button with an accessible name, and a live region for status messages.

    Hint: aria-label names an element that has no visible text.

    Show solution
    <a href="#main" class="skip-link">Skip to content</a>
    <button type="button" aria-label="Close dialog">&times;</button>
    <p role="status" aria-live="polite">Your answer was saved.</p>
    <main id="main">
      <h1>Lesson</h1>
    </main>
  17. BeginnerAccessibility

    17. Native disclosure widget

    Build a FAQ of three questions using details and summary, with the first one open.

    Hint: No JavaScript needed — details is keyboard accessible already.

    Show solution
    <details open>
      <summary>Is the course free?</summary>
      <p>Yes, every chapter is free to read.</p>
    </details>
    <details>
      <summary>Do I need to install anything?</summary>
      <p>No, the compiler runs in your browser.</p>
    </details>
    <details>
      <summary>Is there a certificate?</summary>
      <p>Yes, after you pass the final quiz.</p>
    </details>
  18. IntermediateMetadata & SEO

    18. Metadata for search and sharing

    Write the head of a page with a unique title, description, canonical link and Open Graph tags.

    Hint: og:image should be an absolute URL.

    <head>
    </head>
    Show solution
    <head>
      <meta charset="utf-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1" />
      <title>Learn HTML — 17 chapters and a certificate</title>
      <meta name="description" content="Free HTML course with hands-on examples, a final quiz and a shareable certificate." />
      <link rel="canonical" href="https://playwithcoding.com/languages/html" />
      <meta property="og:title" content="Learn HTML — Play with Coding" />
      <meta property="og:description" content="Free HTML course with hands-on examples and a certificate." />
      <meta property="og:type" content="website" />
      <meta name="twitter:card" content="summary_large_image" />
    </head>
  19. AdvancedMetadata & SEO

    19. Structured data

    Add a JSON-LD script describing an article with a headline, author and date published.

    Hint: The script type is application/ld+json.

    <script></script>
    Show solution
    <script type="application/ld+json">
      {
        "@context": "https://schema.org",
        "@type": "Article",
        "headline": "How to structure an HTML page",
        "author": { "@type": "Person", "name": "Karan Arora" },
        "datePublished": "2026-01-15"
      }
    </script>
  20. BeginnerMetadata & SEO

    20. Escape special characters

    Display the literal text <div class="box"> & © on the page without it being parsed as markup.

    Hint: &lt; &gt; &amp; &quot; &copy;.

    <p></p>
    Show solution
    <p>&lt;div class=&quot;box&quot;&gt; &amp; &copy;</p>
  21. AdvancedPutting it together

    21. Build a complete card

    Build a course card as an article with an image, heading, description, tag list and a call-to-action link.

    Hint: Keep the markup semantic first; styling comes later.

    <article>
    </article>
    Show solution
    <article class="card">
      <img src="/assets/langs/python.png" alt="Python logo" width="64" height="64" />
      <h2><a href="/languages/python">Python</a></h2>
      <p>Readable, powerful and everywhere — 17 chapters with a final quiz.</p>
      <ul>
        <li>Beginner friendly</li>
        <li>In-browser compiler</li>
        <li>Certificate</li>
      </ul>
      <a href="/languages/python" class="cta">Start the course</a>
    </article>
  22. AdvancedPutting it together

    22. A full landing page

    Combine a header with navigation, a hero section, a three-item feature list and a footer into one page.

    Hint: Use section elements with their own headings.

    <!DOCTYPE html>
    <html lang="en">
    </html>
    Show solution
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>Play with Coding — learn by doing</title>
      </head>
      <body>
        <header>
          <nav aria-label="Main">
            <a href="/">Home</a>
            <a href="/languages">Courses</a>
            <a href="/compiler">Compiler</a>
          </nav>
        </header>
        <main>
          <section>
            <h1>Learn to code by writing code</h1>
            <p>Eleven languages, one browser tab.</p>
            <a href="/languages">Browse courses</a>
          </section>
          <section>
            <h2>Why it works</h2>
            <ul>
              <li>Run every example instantly</li>
              <li>Short chapters you can finish</li>
              <li>A quiz and certificate at the end</li>
            </ul>
          </section>
        </main>
        <footer>
          <p>&copy; 2026 Play with Coding</p>
        </footer>
      </body>
    </html>

What to do next

If a whole topic feels shaky, go back to that chapter in the 17-chapter HTML course and re-read it, then return here. When the advanced problems feel routine, take the final HTML quiz and claim your certificate, or open the HTML online compiler and build something of your own.