HTML Headings
What a heading really is in the DOM, the outline it builds, and every attribute it accepts.
The HTMLHeadingElement interface, every global + ARIA attribute headings carry, the document-outline algorithm, and the accessibility rules that follow from it.
Prerequisites
The Learn tab, and a little comfort reading HTML and JavaScript.
Each of <h1>–<h6> is, in the DOM, an instance of HTMLHeadingElement — which adds nothing of its own beyond HTMLElement. That’s the key insight: headings carry no element-specific attributes. Their power is entirely in their semantics — the outline they build — plus the global and ARIA attributes every element shares.
The document outline
Assistive technology builds a navigable tree from your headings. A screen-reader user can jump heading-to-heading; the levels tell them what nests under what. Get the levels right and the page is a clean outline; skip a level and the tree has a hole.
DetailWhatever happened to the HTML5 “outline algorithm”?
HTML5 once proposed that each sectioning element (<section>, <article>) would create its own outline scope, so an h1 inside a nested section would auto-demote. No browser ever implemented it. The living standard removed it — so you must still pick heading levels explicitly. Use one h1 and descend by hand.
Every attribute a heading carries
Headings accept the global attributes (shared by all elements) and ARIA attributes. There are no heading-specific attributes in the modern spec — the old align attribute is deprecated.
| Attribute | What it does |
|---|---|
| id | Unique identifier — a link target (#id) and a JS/CSS hook. |
| class | Space-separated class names for CSS and scripting. |
| style | Inline CSS for this one element (prefer a stylesheet). |
| title | Advisory text shown as a tooltip on hover. |
| lang | Language of the heading’s text (e.g. en, fr) — helps TTS + translation. |
| dir | Text direction: ltr, rtl, or auto. |
| hidden | Removes the element from rendering and the a11y tree. |
| tabindex | Makes the heading focusable / sets tab order (rarely needed). |
| contenteditable | Lets the user edit the heading text in place. |
| draggable | Marks the heading as draggable for drag-and-drop. |
| spellcheck | Hints whether to spell-check editable text. |
| translate | yes/no — whether translation tools should translate the text. |
| data-* | Your own custom data, readable from JS via element.dataset. |
| role | ARIA role override (default role is "heading"). |
| aria-level | Overrides the heading level for assistive tech (1–6, advanced). |
| aria-label | An accessible name when the visible text isn’t enough. |
What you can do with it from JavaScript
- .textContent / .innerText
- Read or set the heading’s text.
- .id / .className / .classList
- Read/modify the id and classes.
- .dataset
- Read/write data-* attributes as an object.
- .getAttribute() / .setAttribute()
- Generic attribute access (e.g. aria-level).
- .scrollIntoView()
- Scroll the page so this heading is visible — great for in-page nav.
- .getBoundingClientRect()
- Measure the heading’s position and size on screen.
- .closest() / .matches()
- Walk up to / test the heading against a selector.
const toc = document.querySelector('#toc'); for (const h of document.querySelectorAll('h2, h3')) { // Ensure every heading has an id to link to. if (!h.id) h.id = h.textContent.trim().toLowerCase().replace(/\s+/g, '-'); const link = document.createElement('a'); link.href = '#' + h.id; link.textContent = h.textContent; link.style.paddingLeft = h.tagName === 'H3' ? '1rem' : '0'; toc.append(link);}Reference
Just need the facts?
The Reference tab is the answer-first index: levels, defaults, and the DOM interface at a glance.
More like this
HTML Headings
h1 through h6 are the page’s table of contents. Use them for structure, never for size — that’s what CSS is for.
HTML Headings
Everything about h1–h6 you’d look up mid-task, with no preamble.
Liked this one?
Pass it on
Discussion
Be the first to ask
Your questions stay private with the team. We can pin answers to share with everyone.
Sign in to ask a question privately on this tutorial.
Sign inNo pinned answers yet for this tutorial.