# Semantic HTML

Semantic elements over div+role, document structure, language, frames, lists, quotes.

## Criteria

| Standard | Criteria                                                                                                                  |
| -------- | ------------------------------------------------------------------------------------------------------------------------- |
| WCAG 2.2 | 1.3.1 Info and Relationships (A), 1.3.2 Meaningful Sequence (A), 3.1.1 Language of Page (A), 3.1.2 Language of Parts (AA) |
| RGAA 4.1 | 2.1–2.2 Frames, 8.1–8.10 Mandatory elements, 9.2–9.4 Document structure                                                   |

### Info and Relationships — WCAG 1.3.1 (A) / RGAA 9.2–9.4, 8.9

Structure conveyed visually must be programmatically determinable. Use semantic HTML: `<nav>`, `<main>`, `<article>`, `<aside>`, `<header>`, `<footer>`. Use `<label>` for form controls, `<th>` + `scope` for data tables, `<ul>`/`<ol>` for lists, `<blockquote>`/`<q>` for quotes. Don't use HTML elements solely for presentation (e.g., `<blockquote>` for indentation).

### Meaningful Sequence — WCAG 1.3.2 (A) / RGAA 10.1–10.3 (partial)

Reading/DOM order must match visual order. Avoid CSS that reorders content (flexbox `order`, grid placement) unless DOM order is already correct.

### Language of Page — WCAG 3.1.1 (A) / RGAA 8.3–8.4

Every page needs `<html lang="...">` with a valid ISO 639 code.

### Language of Parts — WCAG 3.1.2 (AA) / RGAA 8.7–8.8

Mark every language change with `lang` attribute. Code must be valid and relevant.

---

## RGAA 4.1 — Theme 2: Frames (Cadres)

### Criterion 2.1 — Frame title presence (A)

Does every frame have a frame title?

**Test 2.1.1:** Does every frame (`<iframe>` or `<frame>`) have a `title` attribute?

Methodology:

1. Find all frames (`<iframe>` or `<frame>`) in the document.
2. For each frame, verify it has a `title` attribute.
3. If true for every frame, the test passes.

WCAG: 4.1.2 (A) — Technique H64.

### Criterion 2.2 — Frame title relevance (A)

For every frame that has a title, is that title relevant?

**Test 2.2.1:** For every frame (`<iframe>` or `<frame>`) that has a `title` attribute, is the content of that attribute relevant?

Methodology:

1. Find all frames (`<iframe>` or `<frame>`) in the document.
2. For each frame that has a `title` attribute, verify its content is relevant to the frame's content.
3. If true for every frame, the test passes.

WCAG: 4.1.2 (A) — Technique H64.

---

## RGAA 4.1 — Theme 8: Mandatory Elements (Elements obligatoires)

### Criterion 8.1 — Document type presence (A)

Is every page defined by a document type?

**Test 8.1.1:** Is the document type declaration (`doctype` tag) present?

Methodology:

1. Find the DOCTYPE declaration in the document (e.g. `<!DOCTYPE html>`).
2. Verify that:
   - The DOCTYPE tag is placed before the `<html>` tag.
   - The document type is valid.
3. If true, the test passes.

**Test 8.1.2:** Is the document type declaration valid?

Methodology: Same checks as test 8.1.1.

**Test 8.1.3:** If a document type declaration exists, is it placed before the `<html>` tag in the source code?

Methodology: Same checks as test 8.1.1.

WCAG: 4.1.1 (A) — Techniques G134, G192.

### Criterion 8.2 — Valid source code (A)

Does the generated source code conform to the specified document type?

**Test 8.2.1:** For each document type declaration, does the generated source code verify these conditions?

- Tags, attributes, and attribute values follow writing rules.
- Tag nesting is correct.
- Tag opening and closing is correct.
- `id` attribute values are unique within the page.
- Attributes are not duplicated on a single element.

Methodology:

1. Validate the page markup (e.g. via W3C Nu markup checker).
2. In the results, verify:
   - Tags, attributes, and attribute values follow writing rules.
   - Tag nesting is correct.
   - Tag opening and closing is correct.
   - `id` attribute values are unique within the page.
   - Attributes are not duplicated on a single element.
3. If all conditions are met, the test passes.

WCAG: 4.1.1 (A), 4.1.2 (A) — Techniques H74, H93, H94; Failures F70, F77.

### Criterion 8.3 — Default language presence (A)

Is the default language present on every page?

**Test 8.3.1:** Does the default language indication meet one of these conditions?

- The page language indication (`lang` and/or `xml:lang` attribute) is given on the `<html>` element.
- The page language indication (`lang` and/or `xml:lang` attribute) is given on each text element or one of its parent elements.

Methodology:

1. Find the default language indication in the document.
2. Verify the presence of a language indication:
   - Via the `lang` attribute on `<html>` if the code is HTML5 or HTML4.
   - Via both `lang` and `xml:lang` attributes on `<html>` if the code is XHTML 1.0.
   - Via the `xml:lang` attribute on `<html>` if the code is XHTML 1.1.
   - Otherwise, verify the presence of a language indication on each text element or one of its parents.
3. If true, the test passes.

WCAG: 3.1.1 (A) — Technique H57.

### Criterion 8.4 — Default language code relevance (A)

For every page that has a default language, is the language code relevant?

**Test 8.4.1:** Does the language code verify these conditions?

- The language code is valid (conforms to ISO 639-1 or ISO 639-2 and subsequent standards).
- The language code is relevant (indicates the main language of the document).

Methodology:

1. Find the default language indication in the document.
2. Verify the language code is:
   - Valid (conforms to ISO 639-1 or ISO 639-2 and subsequent standards).
   - Relevant (indicates the main language of the document).
3. If true, the test passes.

WCAG: 3.1.1 (A) — Technique H57.

### Criterion 8.5 — Page title presence (A)

Does every page have a page title?

**Test 8.5.1:** Does every page have a page title (`<title>` tag)?

Methodology:

1. Find in the document the title structured via a `<title>` element.
2. If present, the test passes.

WCAG: 2.4.2 (A) — Techniques G88, G127, H25.

Note: Page title relevance is covered in detail in `a11y-navigation.md`.

### Criterion 8.6 — Page title relevance (A)

For every page that has a page title, is that title relevant?

**Test 8.6.1:** For every page that has a page title (`<title>` tag), is the content of that tag relevant?

Methodology:

1. Find in the document the title structured via a `<title>` element.
2. Verify the content of the `<title>` element is sufficiently relevant (it allows finding the page in navigation history or the tab list).
3. If true, the test passes.

WCAG: 2.4.2 (A) — Techniques G88, G127, H25.

### Criterion 8.7 — Language change indication (AA)

Is every language change indicated in the source code (except special cases)?

**Test 8.7.1:** Does every text written in a language different from the default language verify one of these conditions (except special cases)?

- The language indication is given on the element containing the text (`lang` and/or `xml:lang` attribute).
- The language indication is given on one of the parent elements (`lang` and/or `xml:lang` attribute).

Methodology:

1. Find text passages in a foreign language, excluding:
   - Proper nouns.
   - Foreign-origin words present in the dictionary of the document's language.
   - Foreign-origin words in common use whose pronunciation does not cause misunderstanding.
2. Verify that each retained text passage has a language indication (`lang` and/or `xml:lang` attribute on the element itself or one of its parents).
3. If true, the test passes.

Special cases (criterion is non-applicable):

- Proper nouns.
- Foreign common nouns present in the official dictionary of the page's default language.
- Foreign-language terms submitted via a form field and echoed on the page (e.g. search terms).
- Text passages whose language cannot be determined.
- Terms or text passages from a dead or imaginary language with no vocal interpretation.

Technical note: For foreign common nouns absent from the official dictionary but in common usage (e.g. "newsletter"), the criterion applies only when the absence of a language indication could cause misunderstanding during screen reader rendering.

WCAG: 3.1.2 (AA) — Technique H58.

### Criterion 8.8 — Language change code validity and relevance (AA)

Is the language code of each language change valid and relevant?

**Test 8.8.1:** Does the language code of each language change verify these conditions?

- The language code is valid.
- The language code is relevant.

Methodology:

1. For each text passage validated at test 8.7.1, verify that:
   - The language indication is valid (conforms to ISO 639-1 or ISO 639-2).
   - The language indication is relevant (matches the actual language of the text).
2. If true, the test passes.

WCAG: 3.1.2 (AA) — Technique H58.

### Criterion 8.9 — Tags not used solely for presentation (A)

Are tags not used solely for presentation purposes?

**Test 8.9.1:** In every page, tags (except `<div>`, `<span>`, and `<table>`) must not be used solely for presentation. Is this rule respected?

Methodology:

1. Find all semantic elements used for presentation purposes in the document.
2. For each such element, verify that:
   - The element has a `role="presentation"` attribute.
   - The use of this element for presentation purposes remains justified.
3. If true, the test passes.

Technical note: Examples of misused markup include: a `<div>` used as a paragraph, a heading used as a legend, a `<blockquote>` or empty paragraphs or spaces used to create margin effects. Using `role="presentation"` is formally discouraged but may be justified in rare cases — acceptable on a `<blockquote>` or empty paragraph, but non-conformant on a heading. Presentation tables should not use semantic table markup.

WCAG: 1.3.1 (A) — Techniques G115, H88; Failures F43, F92.

### Criterion 8.10 — Reading direction changes (A)

Are changes in reading direction indicated?

**Test 8.10.1:** Is every text whose reading direction differs from the default reading direction contained in a tag with a `dir` attribute?

Methodology:

1. Find text passages that use a language read in the opposite direction from the document's language (e.g. Arabic or Hebrew for a French document).
2. For each text passage, verify it is contained in a tag that has a `dir` attribute.
3. If true for every passage, the test passes.

**Test 8.10.2:** Does every reading direction change (`dir` attribute) verify these conditions?

- The `dir` attribute value is valid (`rtl` or `ltr`).
- The `dir` attribute value is relevant.

Methodology:

1. For each text passage validated at test 8.10.1, verify that:
   - The reading direction indication is valid (`ltr` for left-to-right, `rtl` for right-to-left).
   - The reading direction indication is relevant.
2. If true for every passage, the test passes.

WCAG: 1.3.2 (A) — Technique H56.

---

## RGAA 4.1 — Theme 9: Document Structure (Structuration) — Criteria 9.2–9.4

Note: Criterion 9.1 (headings) is covered in `a11y-headings.md`.

### Criterion 9.2 — Coherent document structure (A)

Is the document structure coherent (except special cases)?

**Test 9.2.1:** Does the document structure verify these conditions (except special cases)?

- The page header zone is structured via a `<header>` tag.
- Main and secondary navigation zones are structured via `<nav>` tags.
- The `<nav>` tag is reserved for structuring main and secondary navigation zones.
- The main content zone is structured via a `<main>` tag.
- The document structure uses a single visible `<main>` tag.
- The page footer zone is structured via a `<footer>` tag.

Methodology:

1. Verify the header zone is structured with a `<header>` element.
2. Verify main and secondary navigation zones are structured with `<nav>` elements.
3. Verify `<nav>` is not used outside of main and secondary navigation zones.
4. Verify the main content zone is structured with a `<main>` element.
5. If the document has multiple `<main>` elements, verify only one is visible (others must have a `hidden` attribute).
6. Verify the footer zone is structured with a `<footer>` element.
7. If true for every content zone, the test passes.

Special cases: When the declared doctype is not HTML5, this criterion is non-applicable.

Technical note: The `<main>` tag may be used multiple times in the same HTML document. However, only one may be visible and readable by assistive technologies at any time — others must have a `hidden` attribute or a style that hides them from assistive technologies. Note that using style alone is insufficient to ensure a single visible `<main>` if stylesheets are disabled.

WCAG: 1.3.1 (A) — Techniques G115, ARIA11.

### Criterion 9.3 — Correct list structure (A)

Is every list correctly structured?

**Test 9.3.1:** Do visually grouped items forming an unordered list verify one of these conditions?

- The list uses `<ul>` and `<li>` HTML tags.
- The list uses WAI-ARIA attributes `role="list"` and `role="listitem"`.

Methodology:

1. Find elements visually grouped as an unordered list in the document.
2. For each list, verify it is structured:
   - Either with `<ul>` and `<li>` elements.
   - Or with elements having WAI-ARIA `role="list"` and `role="listitem"`.
3. If true for every unordered list, the test passes.

**Test 9.3.2:** Do visually grouped items forming an ordered list verify one of these conditions?

- The list uses `<ol>` and `<li>` HTML tags.
- The list uses WAI-ARIA attributes `role="list"` and `role="listitem"`.

Methodology:

1. Find elements visually grouped as an ordered list in the document.
2. For each list, verify it is structured:
   - Either with `<ol>` and `<li>` elements.
   - Or with elements having WAI-ARIA `role="list"` and `role="listitem"`.
3. If true for every ordered list, the test passes.

**Test 9.3.3:** Do items grouped as a description list use `<dl>` and `<dt>`/`<dd>` tags?

Methodology:

1. Find elements visually grouped as a description list in the document.
2. For each list, verify it is structured with `<dl>`, `<dt>`, and `<dd>` elements.
3. If true for every description list, the test passes.

Technical notes:

- WAI-ARIA `role="list"` and `role="listitem"` may require `aria-setsize` and `aria-posinset` when the complete list is not available in the generated DOM at the time of consultation.
- WAI-ARIA roles `role="tree"`, `role="tablist"`, `role="menu"`, `role="combobox"`, and `role="listbox"` are not equivalent to HTML `<ul>` or `<ol>` lists.

WCAG: 1.3.1 (A) — Techniques G115, G153, H40, H48; Failure F2.

### Criterion 9.4 — Correct quotation markup (A)

Is every quotation correctly indicated?

**Test 9.4.1:** Does every short (inline) quotation use a `<q>` tag?

Methodology:

1. Find short (inline) quotations in the document.
2. For each quotation, verify it is structured with a `<q>` element.
3. If true for every short quotation, the test passes.

**Test 9.4.2:** Does every block quotation use a `<blockquote>` tag?

Methodology:

1. Find block quotations in the document.
2. For each block quotation, verify it is structured with a `<blockquote>` element.
3. If true for every block quotation, the test passes.

WCAG: 1.3.1 (A) — Techniques G115, H49; Failure F2.

---

## Patterns

Always prefer semantic elements. ARIA is a last resort — it duplicates what HTML already provides.

```html
<!-- BAD: div soup with ARIA -->
<div role="button" tabindex="0">Submit</div>
<div role="navigation">
  <div role="link" tabindex="0">Home</div>
</div>

<!-- GOOD: semantic HTML -->
<button type="button">Submit</button>
<nav aria-label="Main">
  <a href="/">Home</a>
</nav>
```

Key elements: `<nav>`, `<main>`, `<header>`, `<footer>`, `<article>`, `<section>`, `<button>`, `<a>`.

Only use `<div>` for layout wrappers with no semantic meaning.

**Page language:**

```html
<html lang="fr">
  <body>
    <p>Bienvenue sur notre site.</p>
    <p>Our <span lang="en">privacy policy</span> is available.</p>
  </body>
</html>
```

**Frame titles:**

```html
<iframe src="https://maps.google.com/..." title="Office location map"></iframe>
```

**Lists:**

```html
<ul><!-- unordered --></ul>
<ol><!-- ordered --></ol>
<dl><dt>Term</dt><dd>Definition</dd></dl>
```

**Quotes:**

```html
<q cite="source">Short quote</q>
<blockquote cite="source"><p>Long quote...</p></blockquote>
```

**Text direction:**

```html
<p dir="rtl">نص بالعربية</p>
```
