Curriculum1 of 9
+ Module 03

HTML, the language

Hand-write semantic, accessible HTML, and start designing in the browser.

Phase 0 · Foundations · 9 sections · about 9 minutes

+ 01 / 09

The DOM is a tree

Every HTML page is a tree. Elements nest inside other elements. The browser reads this structure top to bottom, left to right, building a mental map before it renders a pixel.

This tree matters more than you think. Screen readers walk it. Search engines parse it. Your CSS selectors climb it. JavaScript manipulates it. If the tree is wrong, everything downstream breaks.

A tree has a root, branches, and leaves. In HTML, the root is <html>. It branches into <head> and <body>. Everything else nests from there.

+ HTML
1<html>
2 <head>
3 <!-- Metadata: title, links, scripts -->
4 </head>
5 <body>
6 <!-- Content that the user sees -->
7 </body>
8</html>

The browser does not just see HTML. It sees structure, meaning and relationship, and the tree is how it reads all three at once.

The order of nesting determines the reading order for screen readers. It determines which elements are children, which are siblings, which belong to which parent. Get this right and everything else becomes easier.

+ 02 / 09

Semantic HTML beats div soup

You could build the tree with nothing but <div> and classes. Don't.

Semantic elements are the names HTML gives to common page structures. Instead of <div class="navigation">, use <nav>. Instead of <div class="article">, use <article>. Instead of <div class="important text">, use <strong>.

They tell the browser, the screen reader, and the search engine what each part is. A screen reader announces "navigation region" when it encounters <nav>. A search engine knows <article> is main content, not sidebar. CSS inherits meaning from the element type.

Compare these:

+ HTML
1<!-- div soup: meaningless to everyone but you -->
2<div class="header">
3 <div class="nav">
4 <div class="links">
5 <a href="/">Home</a>
6 </div>
7 </div>
8</div>
9 
10<!-- semantic: the browser understands -->
11<header>
12 <nav>
13 <ul>
14 <li><a href="/">Home</a></li>
15 </ul>
16 </nav>
17</header>

Both render identically. That is exactly the problem: nothing on screen tells you which one you built, so there is no feedback loop pushing you toward the better one.

There is a way to check. Switch the rendered view for the announcements a screen reader produces as it walks each tree, and the two stop being interchangeable.

+ Try itlooking

Same pixels. Now listen to them.

Div soup
HomeWork

Recent work

See all
<div class="nav">
  <div class="links">
    <span class="link">Home</span>
    <span class="link">Work</span>
  </div>
</div>
<div class="heading">Recent work</div>
<div class="btn">See all</div>
Semantic
HomeWork

Recent work

See all
<nav aria-label="Main">
  <ul>
    <li><a href="/">Home</a></li>
    <li><a href="/work">Work</a></li>
  </ul>
</nav>
<h2>Recent work</h2>
<button>See all</button>

The announcements are what a screen reader reads out as it walks each tree. The counters are what it can jump between: Tab stops, the headings list, and the landmarks menu.

The three counters are the part worth sitting with. Tab stops, headings and landmarks are the three ways a person navigates a page without a mouse, and the div version scores zero on all three. It is not slightly worse. It is a page that cannot be operated.

The semantic version is also shorter, clearer, and works better for assistive technology. Care about how you build it. A semantic page is easier to style, faster to load, more accessible by default, and honest in its structure.

Key semantic elements:

  • <header>, introductory content at the top of a section
  • <nav>, navigation links
  • <main>, the primary content of the page (use once per page)
  • <article>, a self-contained piece of content
  • <section>, a thematic grouping of content
  • <aside>, tangential content, sidebars
  • <footer>, closing content of a section
  • <h1> through <h6>, headings in order (never skip levels)
  • <strong>, importance (vs. <b>, which is just bold)
  • <em>, emphasis (vs. <i>, which is just italic)
+ 04 / 09

Buttons are for actions, not navigation

A button performs an action. It opens a modal, toggles visibility, submits a form, or runs JavaScript. It doesn't change the URL.

Use <button> for actions. The browser handles all keyboard interaction: Space and Enter both activate. Focus is automatic. Assistive technology announces it as a button.

+ HTML
1<!-- Action: submit a form -->
2<button type="submit">Send</button>
3 
4<!-- Action: toggle something -->
5<button>Show password</button>
6 
7<!-- Action: open a menu -->
8<button>Menu</button>
9 
10<!-- NOT a button: this navigates -->
11<a href="/next">Next</a>

The type attribute on buttons defaults to "button". Use type="submit" to submit a form, type="reset" to clear form fields. Never use a div or span that looks like a button, use the real element.

The key difference: links change the URL. Buttons don't. If clicking it changes the URL, it's a link. If it performs an action on the same page, it's a button.

+ 05 / 09

Forms and labels are accessibility first

Every form field needs a label. Not a placeholder. Not a hint. A real <label> element connected to the input via for and id.

+ HTML
1<!-- Good: label and input connected -->
2<label for="email-input">Email address</label>
3<input type="email" id="email-input" name="email" />
4 
5<!-- Bad: no label -->
6<input type="email" placeholder="your@email.com" />
7 
8<!-- Bad: label not connected -->
9<label>Email address</label>
10<input type="email" />

When the for and id match, something powerful happens:

  • Clicking the label focuses the input
  • On checkboxes and radio buttons, it enlarges the clickable area
  • A screen reader announces the label when the input is focused
  • The form field has semantic meaning

This works from day one. No JavaScript. No framework. This is a11y-from-day-one in action.

Use the right type for each input. type="email" validates email format and shows an email keyboard on mobile. type="number" shows a numeric keyboard. type="password" hides the text. Use these. They're not just styling, they change how the browser and device behave.

For checkboxes and radio buttons, the label becomes the clickable area:

+ HTML
1<input type="checkbox" id="agree" name="agree" />
2<label for="agree">I agree to the terms</label>

Clicking the label text toggles the checkbox. The clickable area is much larger than the small checkbox itself. This is accessibility that also improves usability for everyone.

+ 06 / 09

SVG is a language inside HTML

SVG stands for Scalable Vector Graphics. It's a markup language that lives inside HTML. You can embed SVG directly in an HTML file, just like you nest a <div> inside another <div>.

SVGs scale infinitely without losing quality. A logo stays crisp at 16px or 16000px. Text stays readable. Lines stay sharp. This matters for logos, icons, and illustrations.

You can write SVG the way you write HTML, with elements and attributes. An SVG starts with <svg> and contains shapes: <circle>, <rect>, <path>, <text>, and more.

+ HTML
1<svg viewBox="0 0 24 24" width="24" height="24">
2 <circle
3 cx="12"
4 cy="12"
5 r="10"
6 stroke="currentColor"
7 fill="none"
8 stroke-width="2"
9 />
10 <path d="M12 8v8M8 12h8" stroke="currentColor" stroke-width="2" />
11</svg>

The viewBox attribute defines the coordinate system. Think of it like a canvas where you draw. viewBox="0 0 24 24" means the coordinate space is 24 units wide and 24 units tall. width and height set how large the SVG renders on the page.

You can nest SVG inside HTML, or save it as a file and link it with <img src="icon.svg">. You can also embed it directly in HTML to style it with CSS or JavaScript.

+ 07 / 09

currentColor: the SVG inheritance trick

currentColor is a CSS keyword that means "use the inherited text color of this element."

It's incredibly useful in SVGs and icons. Instead of hardcoding a color into the SVG, you reference the inherited color. Change the text color, and the icon changes too.

+ HTML
1<!-- SVG with currentColor -->
2<svg viewBox="0 0 24 24" width="24" height="24">
3 <circle cx="12" cy="12" r="10" stroke="currentColor" fill="none" />
4</svg>
5 
6<style>
7 /* The circle's stroke inherits the text color */
8 svg {
9 color: blue; /* circle now has blue stroke */
10 }
11 
12 svg:hover {
13 color: red; /* circle now has red stroke on hover */
14 }
15</style>

This is efficient, flexible, and maintains a single source of truth for color. You define the color once (on the parent element or via CSS), and everything that uses currentColor respects it.

This is especially powerful for icon systems. An icon inherits color from the button it's inside, or from the heading it's next to. No need to write separate versions of the icon for different colors.

+ 08 / 09

Build: A type specimen page

You're going to write a semantic HTML page that showcases typography. No CSS frameworks. No classes for layout. Just semantic HTML structure and minimal style tags for fonts and spacing.

The page will demonstrate:

  • Proper heading hierarchy (<h1> through <h6>)
  • Paragraph text
  • Button styles
  • Form fields with connected labels
  • SVG icons that inherit color
  • Navigation links
  • An aside sidebar

Here's your starter code. Hand-write the HTML, paying attention to semantic elements and proper nesting.

+ HTML
1<!DOCTYPE html>
2<html lang="en">
3 <head>
4 <meta charset="UTF-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6 <title>Type Specimen</title>
7 <style>
8 body {
9 font-family: Georgia, serif;
10 line-height: 1.6;
11 margin: 0;
12 padding: 2rem;
13 max-width: 900px;
14 margin: 0 auto;
15 color: #333;
16 }
17 
18 header {
19 border-bottom: 1px solid #ccc;
20 padding-bottom: 1rem;
21 margin-bottom: 2rem;
22 }
23 
24 nav ul {
25 list-style: none;
26 padding: 0;
27 display: flex;
28 gap: 1.5rem;
29 }
30 
31 a {
32 color: #0066cc;
33 text-decoration: none;
34 }
35 
36 a:hover {
37 text-decoration: underline;
38 }
39 
40 button {
41 padding: 0.5rem 1rem;
42 border: 1px solid #ccc;
43 background: white;
44 cursor: pointer;
45 font-size: 1rem;
46 }
47 
48 button:hover {
49 background: #f5f5f5;
50 }
51 
52 input,
53 textarea {
54 padding: 0.5rem;
55 border: 1px solid #ccc;
56 font-family: inherit;
57 }
58 
59 label {
60 display: block;
61 margin-top: 1rem;
62 margin-bottom: 0.25rem;
63 font-weight: bold;
64 }
65 
66 aside {
67 background: #f9f9f9;
68 padding: 1rem;
69 margin: 2rem 0;
70 border-left: 4px solid #0066cc;
71 }
72 
73 svg {
74 display: inline-block;
75 vertical-align: middle;
76 margin-right: 0.5rem;
77 }
78 
79 footer {
80 border-top: 1px solid #ccc;
81 padding-top: 2rem;
82 margin-top: 3rem;
83 text-align: center;
84 color: #666;
85 }
86 </style>
87 </head>
88 <body>
89 <header>
90 <h1>Type Specimen</h1>
91 <nav>
92 <ul>
93 <li><a href="#headings">Headings</a></li>
94 <li><a href="#body">Body text</a></li>
95 <li><a href="#form">Form fields</a></li>
96 </ul>
97 </nav>
98 </header>
99 
100 <main>
101 <section id="headings">
102 <h2>Heading levels</h2>
103 <h3>This is an h3</h3>
104 <p>Each heading level has semantic meaning and a size.</p>
105 <h4>This is an h4</h4>
106 <p>
107 Never skip heading levels. If you need a smaller heading, style an h3
108 with smaller text. Don't jump from h2 to h4.
109 </p>
110 <h5>This is an h5</h5>
111 <h6>This is an h6</h6>
112 </section>
113 
114 <section id="body">
115 <h2>Paragraph text</h2>
116 <p>
117 This is a paragraph. It contains <strong>strong text</strong> and
118 <em>emphasized text</em>. Use strong for importance, em for emphasis.
119 </p>
120 <p>
121 Paragraphs group related sentences together. They're the building
122 block of readable text.
123 </p>
124 </section>
125 
126 <section id="form">
127 <h2>Forms and interaction</h2>
128 
129 <h3>Buttons</h3>
130 <button>Primary action</button>
131 <button>Secondary action</button>
132 
133 <h3>Form fields</h3>
134 <form>
135 <label for="name-input">Name</label>
136 <input type="text" id="name-input" name="name" />
137 
138 <label for="email-input">Email address</label>
139 <input type="email" id="email-input" name="email" />
140 
141 <label for="message-input">Message</label>
142 <textarea id="message-input" name="message" rows="4"></textarea>
143 
144 <label for="subscribe">
145 <input type="checkbox" id="subscribe" name="subscribe" />
146 Subscribe to updates
147 </label>
148 
149 <button type="submit">Send message</button>
150 </form>
151 </section>
152 
153 <section>
154 <h2>SVG icons that inherit color</h2>
155 <p>
156 <svg viewBox="0 0 24 24" width="20" height="20" color="blue">
157 <circle
158 cx="12"
159 cy="12"
160 r="10"
161 stroke="currentColor"
162 fill="none"
163 stroke-width="2"
164 />
165 </svg>
166 This icon inherits blue from the SVG's color attribute.
167 </p>
168 <p>
169 <svg viewBox="0 0 24 24" width="20" height="20" style="color: green;">
170 <circle
171 cx="12"
172 cy="12"
173 r="10"
174 stroke="currentColor"
175 fill="none"
176 stroke-width="2"
177 />
178 </svg>
179 This icon inherits green from inline CSS.
180 </p>
181 </section>
182 </main>
183 
184 <aside>
185 <h3>Design note</h3>
186 <p>
187 This page uses semantic HTML throughout. No divs where semantic elements
188 exist. Every form field has a label. Links have href. Buttons don't
189 navigate.
190 </p>
191 </aside>
192 
193 <footer>
194 <p>&copy; 2026. Built with semantic HTML.</p>
195 </footer>
196 </body>
197</html>

As you write this, notice:

  • Headings are in order. Never skip from h2 to h4.
  • Every form field has a label with a matching id and for.
  • Links have href attributes. Buttons don't.
  • The navigation is a real <nav> with a <ul> list, not a div with classes.
  • The sidebar is an <aside>, not a div.
  • SVG icons use currentColor to inherit color.
  • No divs for layout. Structure comes from semantic elements.
+ 09 / 09

Checkpoint

Testable criteria:

  1. 1Keyboard navigation passes. Tab through the page. Every interactive element (links, form fields, buttons) receives visible focus. Use Tab to move forward, Shift+Tab to move backward. No focus traps. No elements skipped.
  1. 1No div where semantic element exists. Search the HTML for these patterns: - <div class="button">, should be <button> - <div class="nav">, should be <nav> - <div class="header">, should be <header> - <div class="footer">, should be <footer> - <div class="aside">, should be <aside>
  1. 1Form labels are properly connected. For every input, verify: - The input has an id attribute - There is a <label> element with a for attribute - The for matches the input's id - Clicking the label focuses the input
  1. 1SVG icon inherits color via currentColor. Add an SVG icon to the page. Set stroke="currentColor" or fill="currentColor". Change the SVG's color via CSS. The icon color changes.
  1. 1Links have href. Buttons don't. Check that: - Navigation uses <a href="..."> elements - Form actions use <button> elements - No <a> elements without href - No <button> elements with href
  1. 1Heading hierarchy is correct. Use <h1> once per page. Use <h2>, <h3>, etc. in order. Never skip levels (no h2 directly followed by h4). Screen readers rely on this structure.
  1. 1Explain the difference: Why is <strong> different from <b>? Why is <label for="id"> better than a placeholder? Why does semantic HTML matter for a11y?

If all seven criteria pass, you understand this module.

+ Up nextCSS as a systemPreviouslyHow the web runs