Chapter 01
Document Structure
These exercises practise writing the HTML skeleton that every single web page starts with. Do not move on until you can write this from memory.
8 Exercises
EX 01
Easy
Your First HTML Page
+
Task
Create a basic HTML page from scratch. The page should show your name as the main heading and a short sentence about yourself as a paragraph. The browser tab should read "About Me".
- Write all 4 required root elements: DOCTYPE, html, head, body
- Add a <title> that says "About Me"
- Add an <h1> with your name
- Add a <p> with one sentence about yourself
Expected Elements
<!DOCTYPE html>
<html>
<head>
<title>
<body>
<h1>
<p>
✓ Success Criteria
- Page has
<!DOCTYPE html> as the very first line
- Page has exactly one
<html>, one <head>, one <body>
- Browser tab shows "About Me"
- Page displays your name as a visible heading
- Page displays one paragraph of text below the heading
EX 02Easy
Add the Language Attribute
+
Task
Take your page from Exercise 1 and make it accessible and SEO-friendly by adding the language attribute to the html element. Also add the two most important meta tags that every page must have.
- Add lang="en" to your <html> tag
- Add <meta charset="UTF-8"> as the first tag inside <head>
- Add <meta name="viewport" content="width=device-width, initial-scale=1.0">
Expected Elements
<html lang="en">
<meta charset>
<meta viewport>
✓ Success Criteria
<html> tag has lang="en"
<meta charset="UTF-8"> is the first element inside <head>
- Viewport meta tag is present
EX 03Easy
Fix the Broken Skeleton
+
Task
The code below has 5 mistakes. Find and fix all of them. Copy it into the Playground and correct each error.
Starter Code (contains errors)
<!-- Find and fix the 5 mistakes -->
<html lang="en">
<Head>
<title>My page</title>
<meta charset="UTF-8">
</head>
<Body>
<h1>Welcome
<p>This is my first page.</p>
</body>
</html>
✓ Success Criteria — 5 fixes required
- Missing:
<!DOCTYPE html> on line 1
- Wrong case:
<Head> → <head>
- Wrong order: charset must come before title
- Wrong case:
<Body> → <body>
- Missing closing tag:
</h1> after "Welcome"
EX 04Easy
Multiple Headings and Paragraphs
+
Task
Build a simple recipe page. The page does not need to look good — just practice the structure. Use the correct full HTML skeleton and fill in the body with the recipe content listed below.
- Title tag: "Jollof Rice Recipe"
- One <h1>: "How to Make Jollof Rice"
- One <h2>: "Ingredients"
- One <p> listing some ingredients as plain text
- One <h2>: "Instructions"
- One <p> with two sentences of instruction text
Expected Elements
<h1>
<h2> ×2
<p> ×2
✓ Success Criteria
- Full HTML skeleton with DOCTYPE, html[lang], head, body
- Exactly one
<h1>
- Exactly two
<h2> tags
- At least two
<p> tags
EX 05Medium
Write the Skeleton From Memory
+
Task
Close all notes and course materials. Open a blank Playground and write the complete professional HTML skeleton entirely from memory. Do not copy from anywhere. When you are done, compare your result against the checklist below.
- Write every part without looking: DOCTYPE, html[lang], head with charset first, then viewport, then title — then body with at least one h1 and one p
✓ Success Criteria
<!DOCTYPE html> is first
<html lang="en"> wraps everything
<meta charset="UTF-8"> is first inside <head>
- Viewport meta is second
<title> has meaningful text
<body> has at least one heading and one paragraph
- All tags are properly closed
EX 06Medium
Four-Section Article Page
+
Task
Build a simple blog article page with a proper heading hierarchy. The article is titled "Why You Should Learn HTML First". The page must have a clear structure that makes sense even without any CSS styling.
- One <h1>: the article title
- Three <h2> sections: "It Is the Foundation", "It Is Easy to Learn", "It Gets You Results Fast"
- One <p> of text under each <h2>
- Title tag should reflect the article topic
Expected Elements
<h1> ×1
<h2> ×3
<p> ×3
✓ Success Criteria
- Heading hierarchy is H1 → H2 → H2 → H2 with no skipped levels
- Each H2 has at least one paragraph below it
- Full skeleton is present and correct
EX 07Medium
What Goes in Head vs Body?
+
Task
Read the list of items below. Decide whether each one belongs in <head> or <body>. Then build a page that places every item in the correct location.
- The page title
- A main heading visible on screen
- A meta charset tag
- A paragraph of text
- A link to a stylesheet
- A viewport meta tag
- A subheading
- A meta description
✓ Success Criteria
- In <head>: title, charset, viewport, stylesheet link, meta description
- In <body>: main heading (h1), subheading (h2), paragraph of text
- No visible content placed inside <head>
EX 08Challenging
Build a Full News Article Page
+
Task
Combine everything from this chapter into a realistic news article page. The article topic is: "AngelCode Labs Launches Free HTML Course for African Developers". Your page must feel like a real article — structured, readable, and correctly built from the ground up.
- Full skeleton with DOCTYPE, html[lang="en"], charset first, viewport, meaningful title
- One <h1> for the article headline
- Three <h2> sections: "The Problem", "The Solution", "How to Enrol"
- At least one <h3> inside one of the h2 sections
- At least four <p> tags of content
Expected Elements
<h1>
<h2> ×3
<h3>
<p> ×4+
✓ Success Criteria
- Perfect HTML skeleton — all 4 required components present
- Heading hierarchy: H1 → H2 → H3 with no skipped levels
- Page reads like a real news article without any CSS
- No HTML errors (check using the HTML Checker tab)
Chapter 02
Head & Meta Tags
These exercises practise everything that lives inside the <head> — the invisible layer that controls how your page behaves and appears to browsers, search engines, and social platforms.
8 Exercises
EX 01Easy
Write a Perfect Title Tag
+
Task
Create a page for a fictional bakery called "Golden Crust". Write a title tag that is SEO-friendly — keyword first, brand name at the end, under 60 characters total. Avoid vague titles like "Home" or "Welcome".
- Good format: Primary Keyword | Brand Name
- Include a meta description of 150–160 characters describing the bakery
Expected Elements
<title><meta name="description">
✓ Success Criteria
- Title is under 60 characters
- Title follows
Primary Keyword | Brand format
- Meta description is between 150–160 characters
- Description reads naturally and mentions the bakery's purpose
EX 02Easy
Correct Tag Order in <head>
+
Task
The head section below has all the right tags but they are in the wrong order. Rearrange them into the correct order. Remember: charset must always come first.
Starter Code (wrong order — rearrange)
<head>
<title>Golden Crust Bakery | Fresh Bread in Koforidua</title>
<link rel="stylesheet" href="styles.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="UTF-8">
<meta name="description" content="Fresh artisan bread...">
</head>
✓ Correct Order
- 1.
<meta charset>
- 2.
<meta viewport>
- 3.
<title>
- 4.
<meta name="description">
- 5.
<link rel="stylesheet">
EX 03Easy
Add the Robots and Author Meta Tags
+
Task
Add three extra meta tags to a basic page head: a robots tag that tells Google to index the page and follow links, an author tag with your name, and a theme-color tag with a dark colour of your choice.
- <meta name="robots" content="index, follow">
- <meta name="author" content="Your Name">
- <meta name="theme-color" content="#1c1714">
✓ Success Criteria
- Robots meta is present with
index, follow
- Author meta has a real name value
- Theme-color is a valid hex colour code
EX 04Easy
Add a Favicon Link
+
Task
Add a favicon to a page. Since we cannot upload a real file in the playground, use an SVG emoji favicon — a modern technique that requires no image file at all.
- Add a <link rel="icon"> tag using the SVG data URI technique below
- Add a second <link rel="apple-touch-icon"> pointing to "favicon.png"
Starter Code
<!-- SVG emoji favicon — works without any image file -->
<link rel="icon" type="image/svg+xml"
href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🍞</text></svg>">
<!-- Add the apple-touch-icon below -->
✓ Success Criteria
- SVG favicon link is present and complete
- Apple touch icon link is present
- Both are inside <head>
EX 05Medium
Identify Good vs Bad Titles
+
Task
Below are 6 title tags. Identify which 3 are good and which 3 are bad. Then rewrite the 3 bad ones into good ones. Add your improved versions to a real HTML page with a full skeleton.
- "Home Page"
- "Buy Fresh Sourdough Bread Online | Golden Crust"
- "Welcome!!!"
- "Learn JavaScript from Zero to Pro — 30 Day Course | AngelCode Labs"
- "Page 1"
- "Affordable Web Design Services for Small Businesses in Koforidua | DevCraft"
✓ Success Criteria
- Good titles: options 2, 4, 6 — keyword first, brand last, under 65 chars
- Your rewrites of 1, 3, 5 are descriptive, under 60 chars, follow the format
- All 3 rewritten titles are added to a real HTML page
EX 06Medium
Add a Canonical Link
+
Task
You are building a product page for a fictional shoe shop. The page can be found at multiple URLs — with and without the "www", and with filter parameters. Add a canonical link tag to tell Google the official URL, preventing duplicate content penalties.
- The canonical URL should be: https://shoeshop.ng/trainers
- Add it after the meta description in the <head>
✓ Success Criteria
<link rel="canonical" href="https://shoeshop.ng/trainers"> is present
- It is inside <head>, after the meta description
- The href uses the full https:// URL with no trailing slash issues
EX 07Medium
Add a Stylesheet and Deferred Script
+
Task
Practise correct resource loading. Add a stylesheet link and a JavaScript script tag with the correct attributes so neither blocks the page from rendering.
- Add <link rel="stylesheet" href="styles.css"> inside <head>
- Add <script src="app.js" defer></script> as the last element inside <head>
- Explain in a code comment WHY you use defer on the script
✓ Success Criteria
- Stylesheet link is in <head>
- Script tag has the
defer attribute
- A comment explains that defer prevents the script from blocking HTML parsing
EX 08Challenging
Build a Complete Professional <head>
+
Task
Build a complete, production-quality <head> section for a fictional news website called "NaijaTech Daily". Every tag must be present, in the correct order, with meaningful values. This is the standard you should aim for on every real project.
- charset → viewport → title (with keyword) → meta description → author → robots → canonical → preconnect to Google Fonts → stylesheet link → deferred script
Expected Elements
charsetviewporttitle
descriptionauthorrobots
canonicalpreconnectstylesheet
script defer
✓ Success Criteria
- All 10 elements are present in the correct order
- Title is keyword-first and under 60 characters
- Description is 150–160 characters
- Canonical URL uses https:// and a realistic domain
- Script has
defer attribute
Chapter 03
SEO Tags
These exercises focus on writing HTML that search engines understand and reward. Good SEO is not about tricks — it is about using the right tags correctly.
8 Exercises
EX 01Easy
Write Good and Bad Alt Text
+
Task
Add 4 images to a page. Each image must have alt text. Practice writing correct alt text for each type of image listed below.
- A product photo of red running shoes
- A decorative divider line (empty alt required)
- A clickable logo image linking to the homepage
- A chart showing sales data for Q1 2025
✓ Success Criteria
- Product image: alt describes what the image shows including colour and product type
- Decorative image:
alt="" (empty string, not missing)
- Logo link: alt describes the action ("Go to homepage") not the image appearance
- Chart: alt summarises the data the chart shows
EX 02Easy
Fix the Heading Hierarchy
+
Task
The code below has a broken heading hierarchy. Identify each mistake and fix it so the heading order makes logical sense. Never skip heading levels.
Starter Code (broken hierarchy)
<h2>The Best Smartphones of 2025</h2>
<h4>Budget Picks</h4>
<h6>Under ₵80,000</h6>
<h2>Mid-Range Picks</h2>
<h1>Premium Flagship Picks</h1>
✓ Success Criteria
<h1> is the main page heading — move it to the top
- H2 → H3 → H2 → H2 (no skipping from H2 to H4, no jumping to H6)
- Zero heading hierarchy gaps
EX 03Easy
Write Descriptive Link Text
+
Task
Rewrite all 4 links below so the anchor text is descriptive and meaningful. "Click here" and "Read more" are not acceptable anchor text for SEO or accessibility.
<a href="/courses">Click here</a><a href="/html-guide">Read more</a><a href="/about">This page</a><a href="/contact">Here</a>
✓ Success Criteria
- Every link text describes where the link goes or what the user will find
- No link text is "click here", "read more", "here", or "this page"
- All 4 links are on a real HTML page with full skeleton
EX 04Medium
Build an SEO-Optimised Article Head
+
Task
Write the complete head section for a blog post about "The 10 Best Street Foods in Koforidua". Apply all SEO best practices: keyword-rich title, compelling meta description, canonical URL, and robots tag.
✓ Success Criteria
- Title has "Koforidua" and "street food" near the beginning, under 60 chars
- Description is 150–160 chars, reads like an invitation to click
- Canonical URL is a realistic https:// address
- Robots is set to index, follow
EX 05Medium
Image SEO — Width, Height, and Lazy Loading
+
Task
Add 3 images to a product page. Apply all image SEO best practices to every image. The first image is above the fold (hero). The other two are below the fold.
- All images: descriptive alt text, explicit width and height
- Hero image: no lazy loading
- Below-fold images: loading="lazy"
✓ Success Criteria
- All 3 images have descriptive alt text
- All 3 have width and height attributes set
- Hero image has NO loading="lazy"
- The other 2 images have
loading="lazy"
EX 06Medium
One H1 Rule — Find the Violations
+
Task
The page below has multiple H1 violations. Copy it into the Playground, find all the problems, and fix them. Remember: one H1 per page is the rule — but you must also make the heading hierarchy logical.
Starter Code (contains violations)
<body>
<h1>Our Courses</h1>
<h1>HTML for Beginners</h1>
<p>Learn the web from the ground up.</p>
<h1>CSS Mastery</h1>
<p>Style beautiful websites.</p>
<h1>JavaScript Pro</h1>
<p>Build interactive web apps.</p>
</body>
✓ Success Criteria
- Page has exactly one
<h1>
- Course titles are changed to
<h2>
- Heading hierarchy makes logical sense
EX 07Medium
External Link Security
+
Task
Add 3 external links to a page. Each must open in a new tab AND be safe. Use the correct rel attribute combination that prevents the security vulnerability called "reverse tabnapping".
- Link 1: GitHub (regular external site)
- Link 2: A paid affiliate/sponsored product
- Link 3: A user-submitted comment link
✓ Success Criteria
- All 3 links have
target="_blank"
- All 3 links have
rel="noopener noreferrer"
- Sponsored link also has
rel="sponsored" (combined: rel="sponsored noopener noreferrer")
- User link also has
rel="ugc"
EX 08Challenging
Full SEO Audit and Rewrite
+
Task
The page below is a disaster for SEO. It has at least 7 SEO problems. Find every problem and rewrite the page correctly. Use the HTML Checker tab to verify your final score.
Starter Code (7+ SEO problems)
<html>
<head>
<title>Page</title>
</head>
<body>
<h3>Welcome to our website</h3>
<img src="logo.png">
<h1>Products</h1>
<h1>Services</h1>
<a href="/products">Click here</a>
<a href="https://ext.com" target="_blank">External</a>
</body>
</html>
✓ 7 Problems to Fix
- Missing
lang="en" on <html>
- Missing charset, viewport meta tags
- Title is too vague ("Page")
- Missing meta description
- H3 before H1 — wrong hierarchy, page starts with H3
- Multiple H1 tags
- Image has no alt attribute
- Link text "click here" is not descriptive
- External link missing rel="noopener noreferrer"
Chapter 04
Text Tags
Practise the semantic text tags that give meaning to your content — not just appearance. Every tag here communicates something specific to browsers, screen readers, and search engines.
8 Exercises
EX 01Easy
<strong> vs <b> and <em> vs <i>
+
Task
Write a paragraph that correctly uses all four tags. For each one, write a comment explaining WHY you chose that specific tag over its visual twin.
- Use <strong> for a word that is genuinely important
- Use <em> for a word that needs stress emphasis (like change of tone)
- Use <b> for a product name styled bold but not semantically important
- Use <i> for a foreign word or technical term
✓ Success Criteria
- All 4 tags are used at least once
- Comments explain the semantic vs visual distinction
- The context makes the choice of tag feel appropriate
EX 02Easy
Add a Blockquote with Citation
+
Task
Add a famous quote to a page using the correct semantic tags. The quote is by Tim Berners-Lee. The source URL is https://www.w3.org/People/Berners-Lee/.
- Use <blockquote cite="URL"> for the quote container
- The quote text goes inside a <p>
- Use <cite> for the author name below the quote
✓ Success Criteria
<blockquote> has a cite attribute with the URL
- Quote text is inside a
<p> inside the blockquote
- Author name is inside a
<cite> tag
EX 03Easy
Price Change with <del> and <ins>
+
Task
Build a simple product card for a pair of headphones. Show the original price as crossed out and the sale price as the new price. Use the correct semantic tags — not CSS strikethrough on a plain span.
- Original price ₵45,000 → use <del>
- New price ₵29,999 → use <ins>
✓ Success Criteria
<del> wraps the old price
<ins> wraps the new price
- Both appear in the same paragraph or product card context
EX 04Easy
Abbreviations and Time Tags
+
Task
Write a paragraph about web technology that uses at least 3 abbreviations and 1 date. Use the correct tags so the full form appears on hover and the date is machine-readable.
- Abbreviations to use: HTML, CSS, API
- A publication date — today's date in datetime format
✓ Success Criteria
- Each abbreviation uses
<abbr title="full form">
- HTML, CSS, API all have correct expanded forms in their title attributes
- Date uses
<time datetime="YYYY-MM-DD">
EX 05Medium
Inline Code and Keyboard Shortcuts
+
Task
Write a short tutorial paragraph explaining how to open DevTools in a browser. The paragraph must reference a code function and show keyboard shortcuts using the correct semantic tags.
- Use <code> for
console.log() and document.querySelector() - Use <kbd> for Ctrl, Shift, I, and F12 key references
- Use <samp> for one example of browser console output
✓ Success Criteria
- At least 2 uses of
<code>
- At least 3 uses of
<kbd>
- At least 1 use of
<samp>
EX 06Medium
Superscript and Subscript
+
Task
Write a short science fact page with at least 3 correct uses of scientific notation using sub and sup tags. Examples are given below — write new facts of your own using the same pattern.
- Water molecule: H₂O →
H<sub>2</sub>O - Einstein's formula: E=mc² →
mc<sup>2</sup> - CO₂ gas: use <sub>
- Footnote reference [1]: use <sup>
✓ Success Criteria
- At least 2 uses of
<sub> in appropriate scientific context
- At least 2 uses of
<sup>
- All used correctly — subscript lowers the text, superscript raises it
EX 07Medium
Search Result Highlight
+
Task
Simulate a search results page. The user searched for "HTML tutorial". Display 3 search result snippets. In each snippet, the words "HTML" and "tutorial" must be highlighted wherever they appear in the text — like a real search engine does.
- Use <mark> to highlight the search terms
- Each result needs a title (link), a URL, and a description paragraph
✓ Success Criteria
<mark> wraps each occurrence of the search terms
- 3 search results are present
- Each has a title, a URL, and a description
EX 08Challenging
Build a Rich Blog Article Body
+
Task
Write the body content of a blog post titled "Why JavaScript Is the Language of the Web". Use as many semantic text tags as naturally fit. The article should feel like real writing — not a forced list of tags.
- Use <strong> for at least 2 important terms
- Use <em> at least once for stress emphasis
- Include a <blockquote> with a real or fictional tech quote
- Use <code> for at least one code reference
- Use <time> for a date in the article
- Use <mark> once to highlight a key phrase
- Include at least one <abbr>
✓ Success Criteria
- All 7 required tags are used at least once
- The article reads naturally — tags feel appropriate, not forced
- Full HTML skeleton is present
Chapter 05
Links & Media
Links connect the web. Images make pages visual. These exercises cover every type of link and image use case you will encounter on real projects.
8 Exercises
EX 01Easy
Four Types of Links
+
Task
Build a page with exactly four different types of links. Each must be in a <p> tag with a label explaining what type it is.
- An internal link to /about on the same site
- An external link to https://github.com opening in a new tab
- An email link to contact@example.com
- A phone link to +2348012345678
✓ Success Criteria
- Internal link has a relative href starting with /
- External link has target="_blank" and rel="noopener noreferrer"
- Email link uses the mailto: protocol
- Phone link uses the tel: protocol with country code
EX 02Easy
Jump Links Within a Page
+
Task
Build a one-page FAQ. At the top, create a list of 3 question links. Each link must jump to the matching answer further down the page when clicked. This is called an "anchor link" or "jump link".
- Questions at top link to: #q1, #q2, #q3
- Each answer section has the matching id attribute
- Add a "Back to top" link at the bottom pointing to #top
- Add id="top" to your <body> or <h1>
✓ Success Criteria
- 3 jump links at the top with href="#q1" etc.
- 3 answer sections with id="q1" etc.
- Back to top link at the bottom
EX 03Easy
Responsive Product Image
+
Task
Add a product image to a page following all image best practices. The image is a fictional photo of a laptop computer. This image is at the top of the page — above the fold.
- Use a placeholder URL for src: https://via.placeholder.com/800x500
- Write a descriptive alt text about the laptop
- Set width="800" and height="500"
- Do NOT add loading="lazy" — explain in a comment why not
✓ Success Criteria
- Image has a descriptive alt text
- Width and height are both set
- No loading="lazy" on the hero image
- A comment explains that hero images should not be lazy-loaded
EX 04Easy
Clickable Image Link
+
Task
Build a simple course card. The course thumbnail image should be clickable — clicking it takes the user to the course page. Wrap the image in an anchor tag to achieve this.
- Wrap the <img> in an <a href="/html-course">
- The alt text should describe the destination, not the image: "Go to the HTML Course page"
✓ Success Criteria
<img> is wrapped inside <a href="...">
- Alt text describes where the link goes
- Image has width and height attributes
EX 05Medium
Image with Figure and Caption
+
Task
Add 2 images to an article page. Each image must be semantically wrapped with a figure element and have a visible caption below it using the correct HTML tag.
- Use <figure> as the container
- Place the <img> inside <figure>
- Add <figcaption> with a meaningful caption below the image
✓ Success Criteria
- Both images are wrapped in
<figure>
- Both have a
<figcaption>
- Captions describe the image content in one or two sentences
EX 06Medium
Gallery with Lazy Loading
+
Task
Build a simple photo gallery section with 6 images. Since all 6 appear below the page header, they are all below the fold. Apply the correct loading strategy to prevent them from slowing down the initial page load.
- All 6 images: explicit width and height, descriptive alt, loading="lazy"
- Group them inside a <section> with an <h2>Photo Gallery</h2>
- Use placeholder URLs: https://via.placeholder.com/400x300
✓ Success Criteria
- All 6 images have
loading="lazy"
- All 6 have width, height, and alt attributes
- Images are inside a <section> with a heading
Task
Create a resources page with 3 downloadable files. Each link must trigger a download rather than navigating to the file. Give each download a custom filename.
- A PDF guide — should download as "html-beginners-guide.pdf"
- A CSS cheatsheet — should download as "css-cheatsheet.pdf"
- A starter project ZIP — should download as "starter-project.zip"
Starter Code Hint
<!-- The download attribute triggers a file download -->
<a href="files/guide.pdf" download="html-beginners-guide.pdf">
Download HTML Guide (PDF)
</a>
✓ Success Criteria
- All 3 links have the
download attribute
- Each download attribute specifies the filename
- Link text clearly describes what is being downloaded
EX 08Challenging
Build a Portfolio Preview Page
+
Task
Build a simple portfolio page for a fictional photographer called "Adaeze Okafor". The page must showcase her work with images, include contact links, and follow all link and image best practices.
- A header with her name as the H1
- At least 4 portfolio images — each wrapped in <figure><figcaption>
- All below-fold images use lazy loading with width and height
- An email link and an Instagram profile link (external, opens in new tab)
- A "Download CV" link using the download attribute
- A jump link menu at the top linking to #portfolio and #contact sections
✓ Success Criteria
- Full HTML skeleton with proper metadata
- 4 images all in figure+figcaption, lazy-loaded with dimensions
- All external links have rel="noopener noreferrer"
- Download link has the download attribute
- Jump links connect to matching id sections
Chapter 06
Lists & Tables
Lists and tables are among the most commonly used structures in real websites. Master the difference between them — lists for groups of related items, tables for data with relationships between rows and columns.
8 Exercises
EX 01Easy
Build a Navigation Menu
+
Task
Navigation menus are built with unordered lists. Create a navigation bar with 5 links — Home, Courses, Playground, Blog, Contact. The nav must be inside a <nav> element and the links inside an unordered list.
✓ Success Criteria
<nav> wraps the entire navigation
<ul> is inside <nav>
- Each link is inside an
<li> inside the <ul>
- 5 links present with descriptive text and href attributes
EX 02Easy
Step-by-Step Instructions
+
Task
Write a step-by-step guide for "How to submit a project on AngelCode Labs". Use an ordered list because the steps must be followed in a specific order. Include at least 5 steps.
✓ Success Criteria
<ol> is used (not ul — order matters here)
- At least 5
<li> items
- Each step is a clear action the user must take
Task
Build a course curriculum list showing chapters and lessons. The main list shows chapter names. Inside each chapter item, add a nested list of 3 lesson titles. This represents a real-world use case for nested lists.
- 3 chapters in the outer list
- 3 lessons nested inside each chapter
✓ Success Criteria
- Outer
<ul> or <ol> has 3 <li> items
- Each <li> contains a nested
<ul> with 3 lesson items
- Nesting is correct — inner list is INSIDE the <li>, not after it
EX 04Medium
Simple Data Table
+
Task
Build a table comparing 3 smartphones. The table must have proper structure — not just rows and cells. Include a caption, column headers, and a body section. No CSS — just clean HTML.
- Columns: Phone Model, Price, RAM, Camera
- 3 rows of fictional phone data
- Use <caption> for the table title
- Use <thead> with <th scope="col"> for headers
- Use <tbody> for data rows
✓ Success Criteria
<table> has a <caption>
<thead> contains header row with scope="col" on each <th>
<tbody> contains 3 data rows
- 4 columns with consistent data in each row
EX 05Medium
Table with Footer Row
+
Task
Build a monthly sales table with a totals row in the footer. The table shows sales figures for 4 products across 3 months. The <tfoot> row shows the total for each month column.
- Columns: Product Name, January, February, March
- 4 product rows in <tbody>
- A totals row in <tfoot>
✓ Success Criteria
<thead>, <tbody>, and <tfoot> all present
- Footer row has "Total" as the first cell
- Table has a caption
- Column headers have scope="col"
EX 06Medium
Description List — Glossary
+
Task
Build an HTML glossary using a description list. This tag is specifically designed for term-definition pairs — perfect for a glossary, FAQ, or product specifications.
- Define 5 HTML terms: DOCTYPE, semantic, meta tag, canonical, alt text
- Use <dl> as the container
- Each term uses <dt>
- Each definition uses <dd>
✓ Success Criteria
<dl> wraps all terms and definitions
- 5
<dt> terms present
- Each
<dt> has at least one <dd> below it
EX 07Medium
When to Use List vs Table
+
Task
For each item below, decide whether a list or a table is the correct HTML element. Then build each one correctly on a single page. Write a comment above each one explaining your choice.
- A navigation menu
- A pricing comparison of 3 plans with features listed
- A list of ingredients for a recipe
- Student exam results showing names, scores, and grades
- Social media links in a footer
✓ Success Criteria
- Navigation:
<ul> — correct
- Pricing comparison:
<table> — data has row/column relationships
- Ingredients:
<ul> — unordered, no relationships
- Exam results:
<table> — tabular data with relationships
- Social links:
<ul> — a group of links, no relationship between them
EX 08Challenging
Complete Course Catalogue Page
+
Task
Build a complete course catalogue page for AngelCode Labs that uses lists and tables correctly throughout. The page must feel like a real product page.
- Navigation menu using <ul> inside <nav>
- A "What You Will Learn" section with a <ul> of 6 benefits
- A curriculum <ol> of 5 numbered chapters — each with a nested <ul> of 3 lessons
- A pricing comparison <table> (Free vs Pro) with <caption>, <thead scope>, <tbody>, <tfoot>
- A glossary <dl> at the bottom with 3 terms
✓ Success Criteria
- All 5 required sections are present
- Table has caption, thead with scope, tbody, and tfoot
- Nested curriculum list is correctly nested inside <li> tags
- Full HTML skeleton with proper head section
Chapter 07
Forms
Forms are how users interact with websites. Every login page, search box, checkout, and signup form is an HTML form. These exercises cover every form element you will use in real projects.
8 Exercises
EX 01Easy
Label Every Input
+
Task
Build a basic registration form. The rule is simple: every input must have a label connected to it using matching for and id attributes. No orphaned inputs allowed.
- Full name (type="text")
- Email address (type="email")
- Password (type="password")
- A submit button: "Create Account"
✓ Success Criteria
- Every
<input> has a matching <label for="...">
- label's
for value matches input's id value exactly
- Form has
method="POST" and an action attribute
- Submit button text describes the action
EX 02Easy
Required Fields and HTML Validation
+
Task
Build a contact form where some fields are required and some are optional. Use HTML's built-in validation — no JavaScript needed. Try submitting the form with empty fields to see the browser validation in action.
- Name: required, type text
- Email: required, type email (browser validates format)
- Phone: optional, type tel
- Message: required, textarea
- Submit button: "Send Message"
✓ Success Criteria
- Required fields have the
required attribute
- Email field uses
type="email"
- Phone field uses
type="tel"
- Submitting with empty required fields shows browser validation messages
EX 03Easy
Dropdown Select Menu
+
Task
Add a "Course Interest" dropdown to a form. The dropdown must have a prompt option and 5 real choices. Make the dropdown required — the user cannot submit without selecting a valid option.
- Prompt option: "Choose a course…" with value=""
- Options: HTML & SEO, CSS Mastery, JavaScript, PHP, SQL
✓ Success Criteria
<select> has a <label> connected via for/id
- First option has an empty value="" (allows required to work)
- 5 real course options are present
required attribute is on the <select>
EX 04Easy
Radio Buttons and Checkboxes
+
Task
Build a survey form asking students about their learning preferences. Use radio buttons where only one choice is allowed and checkboxes where multiple choices are allowed.
- Radio group: "How do you prefer to learn?" — Videos / Reading / Projects (pick one)
- Checkbox group: "Which devices do you use?" — Phone / Laptop / Tablet (pick any)
Starter Code Hint
<!-- Radio buttons share the same name attribute -->
<fieldset>
<legend>How do you prefer to learn?</legend>
<label>
<input type="radio" name="style" value="videos">
Videos
</label>
</fieldset>
✓ Success Criteria
- Radio buttons all share the same
name attribute
- Each radio/checkbox has a visible label
- Groups are wrapped in
<fieldset> with <legend>
- Checkboxes have different name values or an array name[]
EX 05Medium
GET vs POST — Search Form
+
Task
Build a search form using method="GET". Understand why GET is correct for search forms. Observe what happens in the URL after submitting. Then explain the difference between GET and POST in a code comment.
- A search input with type="search" and name="q"
- A submit button: "Search"
- Form method="GET" and action="/search"
- Write a comment explaining when to use GET vs POST
✓ Success Criteria
- Form uses
method="GET"
- Search input has
type="search" and name="q"
- Comment explains: GET for non-sensitive data/bookmarkable results, POST for sensitive/mutating data
EX 06Medium
Autocomplete and Placeholder
+
Task
Build a checkout address form. Every field must have a placeholder for guidance and the autocomplete attribute so browsers can pre-fill saved addresses. Never use placeholder as a replacement for labels.
- Full name: autocomplete="name"
- Street address: autocomplete="street-address"
- City: autocomplete="address-level2"
- Email: autocomplete="email"
- Phone: autocomplete="tel"
✓ Success Criteria
- Every input has a visible
<label>
- Every input has a descriptive
placeholder
- Every input has the correct
autocomplete value
EX 07Medium
Textarea and Character Limit
+
Task
Build a project submission form. The description textarea must enforce a character limit. Also add a minlength so students cannot submit less than 50 characters.
- Project title: required, maxlength="100"
- GitHub URL: type="url", required
- Description: <textarea>, minlength="50", maxlength="500", rows="6"
- Submit button: "Submit Project"
✓ Success Criteria
- All 3 inputs have their required constraints
- Textarea has both
minlength and maxlength
- URL input uses
type="url"
- All fields have labels and the form has a method
EX 08Challenging
Complete Job Application Form
+
Task
Build a complete job application form for a fictional tech company "CodeHouse Ghana". The form must feel like a real application form — professional, accessible, with every input type represented.
- Full name (text, required)
- Email (email, required, autocomplete)
- Phone (tel, required)
- Date of birth (type="date")
- Position applying for: dropdown with 4 options (select)
- Experience level: radio buttons — Junior / Mid / Senior (fieldset + legend)
- Skills: checkboxes — HTML, CSS, JavaScript, PHP, SQL (fieldset + legend)
- Cover letter: textarea, minlength="100", rows="8"
- Portfolio URL (type="url")
- Resume upload (type="file", accept=".pdf")
- Terms agreement checkbox (required)
- Submit button: "Submit Application"
✓ Success Criteria
- All 12 form elements present with labels
- Radio and checkbox groups inside fieldset+legend
- File input accepts PDF only
- Required fields have the required attribute
- Form uses method="POST"
Chapter 08
Semantic Layout
HTML5 semantic elements give meaning to your page structure. These exercises replace generic divs with elements that communicate purpose — to browsers, search engines, and screen readers.
8 Exercises
EX 01Easy
Replace Every Div with a Semantic Tag
+
Task
The code below uses <div> for everything. Rewrite it using correct semantic HTML5 elements. Every <div> must be replaced with a better tag.
Starter Code (replace all divs)
<div class="header">
<div class="nav">...</div>
</div>
<div class="main">
<div class="article">
<div class="section">...</div>
</div>
<div class="sidebar">...</div>
</div>
<div class="footer">...</div>
✓ Correct Replacements
div.header → <header>
div.nav → <nav>
div.main → <main>
div.article → <article>
div.section → <section>
div.sidebar → <aside>
div.footer → <footer>
EX 02Easy
Build a Page Header
+
Task
Build a site header for a fictional news website "NaijaTech Daily". The header must contain a logo (text-based), a site tagline, and a navigation menu. Structure it correctly using semantic tags.
- Use <header> as the wrapper
- Use a link with <strong> for the logo text
- Use <nav> with a <ul> for the navigation
- Add aria-label="Main navigation" to the nav
✓ Success Criteria
<header> wraps the entire top section
<nav aria-label="Main navigation"> is inside header
- Navigation links are in a
<ul>
EX 03Easy
Article vs Section — When to Use Each
+
Task
Write a short page that correctly uses both <article> and <section>. The page is a blog that has one main article with three content sections inside it.
- One <article> wrapping the entire blog post
- Inside the article: a <header> with H1, then 3 <section> elements, each with its own H2
- A comment above each tag explaining why you chose it
✓ Success Criteria
- One
<article> wrapping the blog post
- 3
<section> elements inside the article
- Each section has its own H2
- Comments explain the semantic difference
EX 04Medium
Build a Full Blog Page Layout
+
Task
Build a complete blog page using only semantic HTML. No CSS. The page structure must be logical and accessible. Use every major semantic element at least once.
- <header>: site name + nav with 3 links
- <main>: contains the article and sidebar
- <article>: the blog post with H1, 2 sections (each H2), and 3 paragraphs
- <aside>: "About the Author" block with H2 and a paragraph
- <footer>: copyright text and one link
✓ Success Criteria
- All 5 required semantic elements present
- Only one <main> on the page
- Article has correct heading hierarchy H1 → H2 → H2
- Aside has its own H2 heading
EX 05Medium
Mark the Active Navigation Link
+
Task
You are on the "Courses" page. The navigation should indicate this to screen reader users. Add the correct ARIA attribute to the active link. Do not use CSS — this is an HTML attribute, not a style.
- Add aria-current="page" to the "Courses" link only
- No other links should have this attribute
✓ Success Criteria
- Exactly one link has
aria-current="page"
- It is on the link that represents the current page
EX 06Medium
Footer with Multiple Columns
+
Task
Build a comprehensive site footer using only HTML. The footer has three sections: a company description, a links column, and a contact column. Each section is a separate <section> inside the footer.
- Section 1: Company name + 1 paragraph description
- Section 2: "Quick Links" H3 + ul with 4 links
- Section 3: "Contact" H3 + email link + phone link
- A bottom bar with copyright text
✓ Success Criteria
<footer> wraps all content
- 3
<section> elements with headings inside footer
- Email uses mailto: and phone uses tel:
EX 07Medium
Article with Nested Header and Footer
+
Task
A <header> and <footer> can appear both at the page level AND inside an <article>. Build a blog post that uses all four of these correctly.
- Page-level <header> with site nav
- Article-level <header> inside <article> — contains H1, author, and publish date using <time>
- Article-level <footer> inside <article> — contains tags/categories
- Page-level <footer> with copyright
✓ Success Criteria
- 2
<header> tags: one page-level, one inside article
- 2
<footer> tags: one page-level, one inside article
- Article header contains H1 and a <time datetime>
EX 08Challenging
Build a Full E-Commerce Homepage
+
Task
Build the HTML structure of a complete e-commerce homepage for a fictional store "LuxCraft Koforidua". Use only semantic HTML — no CSS. The page must feel like a real website when read without styling.
- Site <header> with logo link, nav (with aria-label), and aria-current on current page
- <main> containing: hero <section> (H1 + p), featured products <section> (H2 + 3 article cards), "Why Choose Us" <section> (H2 + ul), a newsletter <form>
- <aside> for a promotional banner
- Site <footer> with 3 column sections and a copyright row
✓ Success Criteria
- Full HTML skeleton with complete head section
- All required semantic elements present
- 3 product <article> cards inside a <section>
- Newsletter form has labeled inputs and a submit button
- No heading levels are skipped
Chapter 09
Multimedia — Audio & Video
Practise embedding native HTML5 media players with correct attributes for performance, accessibility, and browser compatibility.
8 Exercises
EX 01Easy
Basic Video Player
+
Task
Add a video to a page using the <video> element. Include the controls attribute so users can actually play it. Set sensible dimensions and add a poster image.
- Use src="https://www.w3schools.com/html/mov_bbb.mp4" for a real video
- Add controls, width="640", height="360"
- Add poster="https://via.placeholder.com/640x360"
- Add a fallback text message inside <video>
✓ Success Criteria
controls attribute present
- Width and height set
poster attribute has a valid URL
- Fallback text between <video> tags
EX 02Easy
Multiple Video Sources
+
Task
Browsers support different video formats. Provide multiple <source> alternatives so every browser can play your video. The browser picks the first one it supports.
- Use <source> for MP4 (video/mp4) and WebM (video/webm)
- Remove the src attribute from the <video> tag itself
- Add a type attribute to each <source>
✓ Success Criteria
- No
src on the <video> tag itself
- Two
<source> tags with different types
- MP4 source comes before WebM
Task
Add a podcast audio player to a page. Provide two audio format sources and include fallback text for browsers that do not support the audio element.
- <audio controls preload="metadata">
- Source 1: MP3 (audio/mpeg)
- Source 2: OGG (audio/ogg)
✓ Success Criteria
controls is present
preload="metadata" is set
- 2 source tags with correct type values
- Fallback text between <audio> tags
EX 04Easy
Video with Captions
+
Task
Add an accessible subtitle track to a video. Captions make videos accessible for deaf users. Use the <track> element to link a subtitle file.
- Add a <track> element inside <video>
- kind="subtitles", srclang="en", label="English", default
- src="subtitles.vtt" (the file does not need to exist)
✓ Success Criteria
<track> element is inside <video>, after <source> tags
- All 4 required attributes are present: kind, srclang, label, default
EX 05Medium
Figure and Figcaption for Video
+
Task
Wrap a video in a <figure> element and add a <figcaption> that describes what the video is about. This is the semantic way to embed media with a visible caption.
✓ Success Criteria
<figure> wraps the entire video
<figcaption> is inside <figure>, after the <video>
- Caption text describes the video content
EX 06Medium
preload Strategies
+
Task
Build 3 separate video elements with different preload strategies. Write a comment above each one explaining what preload="none", preload="metadata", and preload="auto" each do and when you would use each.
✓ Success Criteria
- 3 video elements, each with a different preload value
- Each has a comment explaining the behaviour and the use case
EX 07Medium
Autoplay Safely
+
Task
Autoplay is blocked by browsers unless the video is muted. Create a video that autoplays correctly as a background hero video. Add a comment explaining why muted is required.
- Attributes needed: autoplay, muted, loop, playsinline
- No controls — this is a background video
- No sound since it is muted — add an aria-hidden="true"
✓ Success Criteria
- All 4 attributes present: autoplay, muted, loop, playsinline
- No controls attribute
- aria-hidden="true" on the video
- Comment explains browser autoplay policy
EX 08Challenging
Course Lesson Page with Video and Audio
+
Task
Build a complete lesson page for an online course. It should have a main video lesson, an audio-only version for download, and a transcript section below.
- Page title and H1: "Lesson 3: HTML Document Structure"
- Main <video> in a <figure><figcaption> with controls, poster, preload="metadata", 2 source formats, and a <track> for subtitles
- <audio> with controls and "Audio-only version" label
- A <section> titled "Transcript" with 3 paragraphs of simulated transcript text
- Navigation links: ← Previous Lesson / Next Lesson →
✓ Success Criteria
- Video has controls, poster, preload, 2 sources, and a track
- Video is wrapped in figure+figcaption
- Audio player is present and labelled
- Transcript section uses <section> with H2
- Navigation links use ← → in the text
Chapter 10
Schema Markup & Open Graph
These exercises teach you to control how your page appears in Google search results and on social media — both are driven entirely by tags in your <head>.
8 Exercises
EX 01Easy
Add All 5 Open Graph Tags
+
Task
Add all 5 required Open Graph meta tags to a blog post page. These control how your page looks when shared on WhatsApp, Facebook, and LinkedIn. The blog post is about "10 HTML Tips Every Developer Should Know".
- og:type = "article"
- og:title = the post title
- og:description = a 1-sentence summary
- og:image = a full https:// URL to an image
- og:url = the canonical URL of the post
✓ Success Criteria
- All 5 OG tags present
- og:image uses a full https:// URL
- og:url matches the canonical link in the head
EX 02Easy
Twitter Card Tags
+
Task
Add Twitter Card tags to the same blog post. Twitter reads different meta tags than Open Graph. Use the summary_large_image card type for a large image preview.
- twitter:card = "summary_large_image"
- twitter:title = same as the page title
- twitter:description = same as meta description
- twitter:image = same image as og:image
✓ Success Criteria
- All 4 twitter: tags present
- twitter:card value is exactly "summary_large_image"
- Note the difference: twitter: uses name attribute, og: uses property attribute
EX 03Easy
Your First JSON-LD Schema
+
Task
Add an Article schema to a blog post. The schema lives in a <script type="application/ld+json"> tag. It tells Google the article type, headline, author, and date.
Starter Code
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "YOUR TITLE HERE",
"author": {
"@type": "Person",
"name": "YOUR NAME HERE"
},
"datePublished": "YYYY-MM-DD",
"image": "https://example.com/image.jpg",
"url": "https://example.com/your-article"
}
</script>
✓ Success Criteria
- script type is exactly "application/ld+json"
- All placeholder values are replaced with real values
- JSON is valid (no missing commas, unclosed braces)
EX 04Medium
Product Schema for an E-Commerce Page
+
Task
Write a Product schema for a fictional pair of headphones. Include price, currency, availability, and an aggregate rating. This is what makes star ratings appear in Google search results.
- @type: "Product"
- name, description, image, brand
- offers: price "29999", priceCurrency "NGN", availability "InStock"
- aggregateRating: ratingValue "4.7", reviewCount "84"
✓ Success Criteria
- @type is "Product"
- offers block has price, priceCurrency, and availability
- aggregateRating block has ratingValue and reviewCount
- JSON syntax is valid
Task
Write an FAQ schema for a course page. FAQ schema can produce accordion-style question dropdowns directly in Google search results. Write 3 questions and answers in JSON-LD format.
- @type: "FAQPage"
- 3 mainEntity items, each with @type: "Question", name, and acceptedAnswer
✓ Success Criteria
- @type is "FAQPage"
- 3 question objects in mainEntity array
- Each question has name and acceptedAnswer with @type "Answer" and text
EX 06Medium
og:type Values — Match the Page
+
Task
Build 3 separate mini head sections, each for a different page type. Each must use the correct og:type value for its content type. Write a comment explaining why each type is correct.
- Homepage of a company website
- A blog post article
- A product page on a shop
✓ Success Criteria
- Homepage:
og:type = "website"
- Blog post:
og:type = "article"
- Product:
og:type = "product"
- Comments explain each choice
EX 07Medium
Organization Schema
+
Task
Write an Organization schema for AngelCode Labs. This is typically added to the homepage and tells Google about the brand — name, URL, logo, and contact details. This helps with Google's Knowledge Panel.
- @type: "EducationalOrganization"
- name, url, logo (image URL), description
- sameAs: array of 2 fictional social media profile URLs
✓ Success Criteria
- @type is "EducationalOrganization"
- All required fields present
- sameAs is an array with at least 2 entries
EX 08Challenging
Full Social + Schema Head Section
+
Task
Build the complete <head> section for a blog article. It must be production-ready — every SEO, social, and schema tag must be present and correct. This is the standard for a professional blog post.
- All basic meta tags (charset, viewport, title, description, robots, canonical, author)
- All 5 Open Graph tags + og:site_name
- All 4 Twitter Card tags
- Article JSON-LD schema with author, datePublished, image, url, publisher
- BreadcrumbList JSON-LD schema with 3 levels: Home → Blog → Current Article
✓ Success Criteria
- All basic meta tags present in correct order
- 6 Open Graph tags (including og:site_name)
- 4 Twitter tags
- 2 JSON-LD scripts: Article and BreadcrumbList
- All JSON is valid syntax
Chapter 11
Accessibility — ARIA & Best Practices
Accessibility is not optional. These exercises teach you to build HTML that works for every user, including people who rely on screen readers, keyboard navigation, and other assistive technologies.
8 Exercises
EX 01Easy
Add a Skip Navigation Link
+
Task
Add a skip navigation link to a page. This must be the very first focusable element in the body. It should jump to the main content area when activated. Without it, keyboard users must Tab through every navigation link on every page load.
- Place it as the absolute first child of <body>
- href="#main-content" — links to the <main id="main-content"> element
✓ Success Criteria
- Skip link is first element inside
<body>
- href matches the id on <main>
<main id="main-content"> exists on the page
EX 02Easy
Label an Icon Button
+
Task
Icon buttons (a burger menu, a search icon, a close button) have no visible text. Without an ARIA label, screen reader users hear "button" with no context. Fix all 3 buttons below.
- Hamburger menu button → aria-label="Open navigation menu"
- Search button → aria-label="Search the site"
- Close button → aria-label="Close dialog"
- Add aria-hidden="true" to the icon/emoji inside each button
✓ Success Criteria
- All 3 buttons have descriptive
aria-label
- All icons have
aria-hidden="true"
EX 03Easy
Form Error Message
+
Task
Build a form field that shows an error state. The error message must be programmatically linked to the input — a screen reader user must hear the error when they focus the field.
- Add aria-invalid="true" to the input when it has an error
- Add aria-describedby="email-error" to the input
- Add id="email-error" and role="alert" to the error message span
✓ Success Criteria
- Input has
aria-invalid="true" and aria-describedby="email-error"
- Error message has matching
id="email-error"
- Error element has
role="alert"
EX 04Medium
Accessible Accordion
+
Task
Build the HTML structure of an accordion FAQ — two questions that expand/collapse. You will not add JavaScript, but mark up the ARIA state correctly so the structure is ready for it.
- Each question is a <button> with aria-expanded="false"
- Each answer panel has id connected via aria-controls on the button
- Two <dt><dd> pairs — or use divs with appropriate roles
✓ Success Criteria
- Buttons have
aria-expanded="false"
- Buttons have
aria-controls="panel-id"
- Answer panels have matching
id attributes
EX 05Medium
Multiple Nav Regions
+
Task
A page has 3 navigation areas: main navigation, breadcrumb navigation, and footer navigation. Without labels, screen readers cannot tell them apart. Label each one.
- Main nav: aria-label="Main navigation"
- Breadcrumb nav: aria-label="Breadcrumb"
- Footer nav: aria-label="Footer navigation"
✓ Success Criteria
- 3 <nav> elements, each with a distinct aria-label
- No two nav elements have the same label
EX 06Medium
Native Dialog Modal
+
Task
Build an accessible modal dialog using the native HTML <dialog> element. It handles focus trapping and keyboard navigation automatically — far better than a div-based custom modal.
- Use <dialog aria-labelledby="modal-title">
- H2 with id="modal-title" as the dialog heading
- A confirm button with autofocus
- A cancel button
✓ Success Criteria
<dialog> has aria-labelledby pointing to the heading id
- H2 id matches the aria-labelledby value
- First action button has
autofocus
EX 07Medium
Live Region for Dynamic Content
+
Task
Build a notification area that would announce messages to screen readers automatically when content changes. Without aria-live, screen reader users never hear dynamic updates like "3 new messages" or "Your file has been saved".
- A div with aria-live="polite" and aria-atomic="true" for non-urgent updates
- A separate div with role="alert" for urgent messages
- Write comments explaining the difference between polite and assertive
✓ Success Criteria
- One element with
aria-live="polite" and aria-atomic="true"
- One element with
role="alert" (implicitly assertive)
- Comments explain: polite waits for user pause, assertive interrupts immediately
EX 08Challenging
Accessibility Audit — Find and Fix 8 Issues
+
Task
The page below has 8 accessibility violations. Find every one and fix it. Use the HTML Checker tab to verify your final accessibility score.
Starter Code (8 violations)
<html>
<body>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
<main>
<img src="hero.jpg">
<input type="text" placeholder="Name">
<input type="email" placeholder="Email">
<button>🔍</button>
<table>
<tr><th>Name</th><th>Score</th></tr>
</table>
</main>
</body>
</html>
✓ 8 Issues to Fix
- Missing lang="en" on <html>
- Missing skip navigation link at top of body
- Nav missing aria-label
- Image has no alt attribute
- First input has no <label>
- Second input has no <label>
- Icon button has no aria-label (just a 🔍 emoji)
- Table headers missing scope="col" and table has no caption
Chapter 12
HTML Best Practices & Optimisation
These exercises bring everything together. Apply professional HTML standards — performance, SEO, accessibility, and clean code — to build pages that are ready for the real web.
8 Exercises
EX 01Easy
Defer Your Scripts
+
Task
A page has 3 script tags in the wrong place with no loading strategy. Identify which attribute each script should have and move/update them correctly.
- app.js — main site script, needs the DOM to be ready
- analytics.js — tracking script, runs independently of DOM
- polyfill.js — must run before any other script
✓ Success Criteria
- app.js uses
defer — loads in background, runs after DOM
- analytics.js uses
async — loads and runs independently
- polyfill.js has no defer or async — runs synchronously before others
EX 02Easy
Add Width and Height to All Images
+
Task
A page has 4 images with no dimensions. The page "jumps" as images load — this is called Cumulative Layout Shift (CLS) and it hurts your Google ranking. Fix all 4 images by adding explicit width and height attributes.
- Hero image: 1200 × 600
- Product image: 600 × 400
- Author avatar: 80 × 80
- Thumbnail: 300 × 200
✓ Success Criteria
- All 4 images have both
width and height attributes
- Values match the actual aspect ratio of the image
EX 03Easy
Correct Lazy Loading
+
Task
A page has 6 images. The first image is the hero — above the fold. The remaining 5 are below the fold. Apply the correct loading strategy to each image with a comment explaining the decision.
✓ Success Criteria
- Hero image has NO
loading="lazy" — comment explains why
- All 5 below-fold images have
loading="lazy"
EX 04Medium
preconnect for External Resources
+
Task
A page loads Google Fonts, a CDN-hosted library, and a video from a third-party CDN. Add preconnect hints for each external domain to speed up resource loading. Write a comment explaining what preconnect does.
- fonts.googleapis.com
- fonts.gstatic.com (also needs crossorigin attribute)
- cdnjs.cloudflare.com
✓ Success Criteria
- 3
<link rel="preconnect"> tags present
- fonts.gstatic.com has
crossorigin attribute
- Comment explains: preconnect opens the TCP connection early, before the browser finds a resource to request
EX 05Medium
Use a <picture> Element
+
Task
Use the <picture> element to serve a modern WebP image to browsers that support it, with a JPEG fallback for older browsers. This can reduce image size by 25–35%.
Starter Code
<!-- Browser picks the first <source> it supports -->
<picture>
<source type="image/webp" srcset="hero.webp">
<!-- Add the JPEG fallback <img> here -->
</picture>
✓ Success Criteria
- <picture> wraps everything
- <source type="image/webp"> is first
- <img> fallback with alt, width, height is last inside <picture>
EX 06Medium
Validate Your HTML
+
Task
Build a page with 5 intentional HTML errors. Then use the HTML Checker tab to find them all. Fix each one and confirm the checker shows 0 errors. The goal is to learn what validation catches.
- An unclosed <p> tag
- An <img> with no alt attribute
- A <button> inside a <button> (illegal nesting)
- A <li> not inside a <ul> or <ol>
- A <section> with no heading
✓ Success Criteria
- Build the page with errors first — observe what the checker reports
- Fix all 5 errors one by one
- HTML Checker shows 0 validation errors
EX 07Medium
Write Meaningful Comments
+
Task
Add meaningful comments to a page skeleton. A good comment explains WHY something is done a certain way — not just WHAT it is. Comments that just describe the tag are useless. Explain the reasoning.
- Why charset must be first
- Why not to lazy-load the hero image
- Why defer is used on the script
- Why one H1 only
- Why external links need rel="noopener noreferrer"
✓ Success Criteria
- 5 comments present — each explaining the reasoning
- Comments explain WHY, not just what the code does
- Written in plain English a beginner can understand
EX 08Challenging
The Perfect Page — Score 100 on the HTML Checker
+
Task
Build a page that passes every single check in the HTML Checker tab with a score of 100/100. This is the ultimate exercise — it requires applying every concept from all 12 chapters correctly at the same time.
- DOCTYPE, html[lang], charset, viewport, title, description, robots, canonical
- All 5 OG tags, 4 Twitter tags, JSON-LD Article schema
- Skip link → header[nav+aria-label+aria-current] → main → article → aside → footer
- One H1, correct H2/H3 hierarchy, no skipped levels
- All images: alt, width, height, correct lazy/eager loading
- All form inputs: labels, required fields, autocomplete
- Table with caption, thead scope, tbody, tfoot
- defer on scripts, preconnect for external resources
✓ Success Criteria
- HTML Checker score: 100 / 100
- Every green check — zero red or yellow warnings
- The page reads as a coherent, realistic website without any CSS
Ready to Test Your Code?
Open the Playground and work through each exercise. Use the HTML Checker tab to verify your answers.
⚡ Open Playground