name: structuring-semantic-html description: Structures HTML documents semantically — landmarks, heading hierarchy, meaningful lists/tables/figures, and SEO/meta/Open Graph tags. Use when the user asks to write or review the HTML structure of a page, fix heading levels, add landmarks, improve SEO markup or social previews, or decide between a div and a semantic element. Do not use for ARIA attributes, keyboard, or screen-reader work (ensuring-accessibility) or for parsing/editing existing HTML files programmatically (processing-html).
Structuring Semantic HTML
When to use / when NOT to use
- Use for: authoring or reviewing page structure — landmarks, headings, sectioning, lists/tables/figures,
<head>metadata, Open Graph/Twitter cards. - Do NOT use for: ARIA roles/states, focus management, screen-reader testing (→ ensuring-accessibility); programmatic parsing or bulk editing of HTML files (→ processing-html); visual styling.
Core rules
-
One
<main>per page, every byte of content inside a landmark.- ✅
<header>→<nav>→<main>→<footer>, asides in<aside> - ❌ Content floating in
<body>between landmark regions
- ✅
-
Exactly one
<h1>; heading levels never skip down.- ✅
h1 → h2 → h3, next section starts back ath2 - ❌
h1 → h3because the h3 "looks right" — fix size with CSS, not level
- ✅
-
Element by meaning, div only when no element carries the meaning.
- ✅
<button>for actions,<a href>for navigation,<time datetime="2026-08-05">,<address>,<dl>for key–value pairs - ❌
<div class="button" onclick=…>,<span class="date">
- ✅
-
Tables for data, never for layout; always
<caption>+<th scope>.- ✅
<table><caption>Q2 revenue</caption><thead><tr><th scope="col">… - ❌ A grid of divs presenting tabular data, or a table used to position content
- ✅
-
Sectioning:
<article>= self-contained/syndicatable,<section>= titled thematic group (must contain a heading),<div>= styling hook only. -
<figure>+<figcaption>for any image/chart/code the text refers to.- ✅
<figure><img src="chart.png" alt="Revenue grew 40% in Q2"><figcaption>Fig 1. Quarterly revenue</figcaption></figure> - ❌ An image and an italic paragraph pretending to be a caption
- ✅
-
Minimum viable
<head>:<meta charset="utf-8">,<meta name="viewport" content="width=device-width, initial-scale=1">, unique<title>(≤60 chars, page-specific first),<meta name="description">(≤160 chars), canonical URL. Add Open Graph (og:title,og:description,og:image1200×630,og:url,og:type) and<meta name="twitter:card" content="summary_large_image">for any shareable page. -
Navigation is a list.
- ✅
<nav aria-label="Main"><ul><li><a …>(thearia-labelhere names the landmark; deeper ARIA belongs to ensuring-accessibility) - ❌ A row of bare
<a>tags or divs
- ✅
Workflow
- Outline the content hierarchy first (what is the one h1; what are the sections) — before writing any tags.
- Lay down landmarks, then headings, then flow content, choosing elements by rule 3.
- Fill the
<head>per rule 7. - Self-review: exactly one
<h1>? No skipped heading levels (grep<h[1-6]and read the sequence)? All content inside landmarks? Every<section>has a heading? Title and description unique and within length?
Edge cases & failure modes
- Single-page apps: the rules apply to the rendered DOM — verify the hydrated output, not just the template.
- Multiple h1s from a CMS/theme: demote all but the page's main topic; adjust sizes in CSS.
- No semantic element fits (pure styling wrapper): use
<div>without guilt — forcing<section>everywhere is as wrong as div-soup. - Legacy layout tables: convert to CSS layout only when asked; otherwise flag it and move on.
References
Copy-paste page skeletons, meta blocks, and data-table patterns: see references/patterns.md