HTML Document Structure and Semantic Elements Explained
Web DevelopmentLesson 1 of 46 min read
What you'll learn
- Write a valid HTML document with doctype, lang, charset, viewport and title
- Choose between header, nav, main, article, section, aside and footer for each part of a page
- Explain why a div-only page is harder for browsers, screen readers and search engines to understand
- Predict how the browser repairs invalid nesting such as a div inside a paragraph
On this page
Imagine the Harbour Street Library asks you to build a page for its late-night study week. A colleague has already sketched it: fourteen <div> elements, each with a class like top, menu-box or side-thing. It looks fine in a browser. Yet a screen reader announces nothing but "group, group, group", a search engine cannot tell the event details from the footer small print, and you cannot tell which div is which when you return in three months. This lesson is about replacing those anonymous boxes with elements that say what they are.
The skeleton every document needs
An HTML document is a tree of elements. The browser reads your text, builds that tree (the DOM), then paints it. Four parts of the skeleton are not optional in practice: the doctype, the html element with a language, a head for information about the page, and a body for what people see.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Late-Night Study Week | Harbour Street Library</title>
</head>
<body>
<h1>Late-Night Study Week</h1>
<p>The reading room stays open until 10 pm, Monday to Thursday.</p>
</body>
</html>Open this file and you see a bold, large heading with a single paragraph below it, both pushed in from the edges by the browser's default body margin. The words "Late-Night Study Week | Harbour Street Library" appear in the browser tab, not on the page. That is the job of <title>: it also becomes the bookmark name and the headline in search results.
<!DOCTYPE html>switches the browser into standards mode. Without it, browsers fall back to quirks mode and apply decades-old rendering behaviour.lang="en"tells screen readers which pronunciation rules to use and lets browsers offer correct translation and hyphenation.<meta charset="utf-8">declares the text encoding so characters such as the pound sign or an accented name do not turn into question marks. Keep it within the first 1024 bytes of the file.- The viewport meta tag stops phones from pretending to be a 980-pixel-wide desktop. You will need it as soon as you write responsive CSS.
Say what the content is: semantic elements
A semantic element carries meaning in its name. <nav> is a set of navigation links, <main> is the unique central content of the page, <footer> is the closing information for its nearest section or page. Browsers give these meaning through the accessibility tree, which is why a screen reader user can press a single key to jump to the navigation or skip straight to the main content.
| Element | Meaning | How many per page | Typical content |
|---|---|---|---|
header | Introductory content for the page or a section | Any number | Site name, logo, headline, byline |
nav | A block of major navigation links | A few, label them if several | Main menu, breadcrumbs, table of contents |
main | The central content unique to this page | One visible at a time | Everything except repeated chrome |
article | Self-contained item that makes sense on its own | Any number | News item, event listing, forum post |
section | A themed group of content, normally with a heading | Any number | A chapter of a longer page |
aside | Content tangentially related to its surroundings | Any number | Related links, a pull quote, a notice |
footer | Closing information for the page or a section | Any number | Contact details, copyright, policies |
Here is the library page rebuilt with those elements. Read it and try to sketch what it will look like before the description below.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Late-Night Study Week | Harbour Street Library</title>
</head>
<body>
<header>
<h1>Harbour Street Library</h1>
<nav aria-label="Main">
<a href="/">Home</a>
<a href="/events">Events</a>
<a href="/visit">Visit us</a>
</nav>
</header>
<main>
<article>
<h2>Late-Night Study Week</h2>
<p>The reading room stays open until 10 pm, Monday to Thursday.</p>
<section>
<h3>What is available</h3>
<ul>
<li>Silent desks on the second floor</li>
<li>Free tea at 8 pm</li>
</ul>
</section>
<section>
<h3>Who to ask</h3>
<p>Staff wear green lanyards and can book a group room for you.</p>
</section>
</article>
<aside>
<h2>Good to know</h2>
<p>The side entrance is step-free.</p>
</aside>
</main>
<footer>
<p>12 Harbour Street. Open Monday to Saturday.</p>
</footer>
</body>
</html>With no CSS, the browser stacks everything in source order. You see the large site name, then three links sitting on one line with spaces between them (links are inline elements), then the article heading, its paragraph, two sub-headings with a bulleted list under the first, the aside heading and note, and finally the address line. It looks plain, but the structure is rich: a screen reader can list the landmarks (banner, navigation, main, complementary, contentinfo) and jump between them.
What the browser does with invalid nesting
HTML parsers never throw errors the way a compiler does. They quietly repair what you wrote, which can surprise you. Some elements, such as p, can only contain phrasing content (text and inline elements). Put a block inside and the parser closes the paragraph early.
You write:
<p>Doors open <div>at 9</div> sharp.</p>
The parser builds:
<p>Doors open </p>
<div>at 9</div>
sharp.
<p></p> <- the stray </p> creates an empty paragraphYour CSS selectors, spacing and tests will then be working against a tree you never wrote. An HTML validator catches these problems before they cost you an afternoon.
Block, inline and why order in the source matters
Block elements such as p, h1, ul and article start on a new line and fill the available width. Inline elements such as a, strong and span flow within a line of text. Keep your source order logical, because keyboard users tab through links in source order and screen readers read in source order, however you later rearrange things visually with CSS.
Common mistakes
- Forgetting the doctype. The page renders in quirks mode, so box sizes and table fonts behave oddly, and the validator reports
Start tag seen without seeing a doctype first. - Using `<br>` or empty paragraphs for spacing. Screen readers announce the empty paragraphs and the gaps break the moment someone changes font size. Spacing is CSS work.
- More than one visible `<main>`. The validator complains that a document must not have more than one visible main element, and landmark navigation becomes ambiguous.
- Skipping `lang`. A screen reader may read English text with the wrong voice, and Lighthouse reports
<html> element does not have a [lang] attribute. - Picking elements for their default look. Using
blockquoteto indent a paragraph orh3because it is the right size misleads assistive technology. Choose by meaning, restyle with CSS.
How this shows up in real projects and interviews
In a React or Next.js codebase you will still write header, nav, main and footer, only inside JSX, and accessibility audits run against the final HTML. Interviewers for front-end roles often ask "what is semantic HTML and why does it matter?" The strong answer names three beneficiaries (assistive technology, search engines, future maintainers) and gives a concrete example such as replacing a clickable div with a real button. If you later build components, see React Components and Props and keep the same discipline: a component's root element should be the most meaningful one available.
Try it yourself
Build a page for a fictional community swimming pool. Include a header with site name and a labelled nav of three links, a main containing one article about a new lane-swimming timetable (with two sections), an aside with a safety reminder, and a footer with the opening hours. Run it through the W3C validator and fix every message.
Show a hint
Start from the minimal document above, then add one landmark at a time. Check that you used exactly one h1 and that every section starts with a heading.
Key takeaways
- A valid page needs a doctype, an
htmlelement withlang, aheadwith charset, viewport and title, and abody. - Semantic elements describe what content is;
divandspandescribe nothing and should be the fallback. - Use one visible
main, label repeatednavelements, and pickarticlefor self-contained items. - Parsers silently repair invalid nesting, so validate your markup instead of trusting that it looks right.
Test yourself
A trick from this lesson's ride: The doctype is a mode switch for the browser, not a label describing your page. Four more tricks like it wait along the route, each followed by a question.
Frequently asked questions
What is the difference between div and section in HTML?
A section is a themed group of content that normally starts with a heading and shows up in the document outline. A div has no meaning and is only a container for styling or scripting. Use section when the group has a topic of its own, and div when you just need a wrapper.
Do I need the doctype and html lang attribute?
Yes. The doctype keeps browsers out of quirks mode, which changes how some layouts and tables render. The lang attribute lets screen readers pick the right pronunciation and lets browsers translate and hyphenate correctly. Both cost one short line each.
Can I have more than one h1 on a page?
Browsers allow it, but the heading outline algorithm that once made it safe was never implemented by browsers. The practical advice is one h1 per page that names the main topic, then h2 to h6 in order without skipping levels.