The page navigation is complete. You may now navigate the page content as you wish.
Skip to main content

Content and page structure

How a page is structured, and how its headings, text and microcopy are written, so people find what they came for without reading everything.

A page works when someone can scan it and find the one thing they came for. Headings carry that scan, so the outline is decided before the prose is written.

Four rules to start with

These four decide most content questions. Everything further down this page follows from them, and the page itself is written to obey them.

  1. Lead with the task. Open a page, and every section in it, with what the reader came to do. Background, caveats and edge cases come after.
  2. One page, one job. A page that needs two h1s is two pages.
  3. Structure is semantics, not size. An element is an h1–h6 because of where it sits in the outline. Its size comes from the type scale, and the two are set independently.
  4. Scanning comes before reading. Most people read the headings, the first words of each paragraph, and the lists. Those alone have to tell the story.

Guidance that already exists

This page covers structure: the outline, the heading levels, the length of a line and the words in the interface. Wording, grammar, punctuation and spelling are written down elsewhere on this site, and are not repeated here.

Where What it covers
Voice and tone What we sound like, and what to avoid sounding like
Writing style Sentence case, "you" and "we", active voice, acronyms, the Oxford comma, spelling
Tables Icons, links, badges and empty cells inside a row
Date and time Absolute dates, relative dates and time zones
Accessibility Landmarks, page titles, labels and accessible names
Typography The type scale that heading sizes come from

Every component page carries a Content tab with the wording rules for that component. Start with Button, Alert, Toast and Form primitives: most of the microcopy in a product is one of those four.

Component Its Content tab covers
Badge Status labels, and keeping one word for one state
Tag Truncation past about 20 characters
Dropdown List items short enough to scan
Select Option wording, and not repeating the first word
Inline link Which words to wrap in the link
Standalone link Using the same verb for the same action
Modal Action labels in the footer
Tabs Tab labels that predict their panel
Tooltip Text only, and about 80 characters of it
Rich tooltip When structured content belongs in a bubble
Segmented group Whether the group needs a label of its own
Stepper list Step titles and descriptions
Stepper nav Step titles, and what stays out of them

Page outline

One h1, then two to five sections on an app screen and three to seven in documentation. Past that the page is doing two jobs: split it, or move the parts few people need into an accordion.

Rule App screen Documentation
h1 per page Exactly one Exactly one
h2 sections 2–5 3–7
Deepest level h3 h4, rarely
Skipping a level Never Never
  • The h1 says the same thing as the page <title> and as the navigation item the reader clicked.
  • Every section opens with its heading. Under the h1, no more than two sentences before the first h2.
  • A heading with nothing under it is not a heading. Never use one for emphasis.

Heading level and size

Pick the level from the outline, then the size from the type scale. The two are independent, so an h3 can be large and an h1 small when the design asks for it.

Level Style Use
h1 display-500 bold The page title
h2 display-300 semibold A section
h3 display-200 semibold A subsection
h4 body-300 semibold Documentation only

A component that sets its own title size keeps it. A modal, an alert and a page header are each drawn as a whole, and changing one size inside them breaks it.

Headings inside components

Components that render a title put it in a div unless you say otherwise, because most of those titles sit inside a card or a dialog rather than in the page outline. When a title does belong to the outline, set title-tag to the level the outline asks for.

Leaving it out costs a screen-reader user the page structure, which is the whole point of WCAG 1.3.1.

Accordion, Stepper list, Stepper nav, Application state, Page header and Code block all take title-tag. The Code tab shows the markup for each of them.

Writing headings

A heading labels what is under it; it is not a sentence about it. Two to six words, the keyword first, in sentence case.

  • Sentence case, as Writing style sets out: the first word and proper nouns, nothing else.
  • Front-load the keyword. "Billing settings", not "Settings for billing".
  • Name the content or the task. "Overview", "Introduction", "Misc" and "Other" name nothing.
  • No full stop. A question mark only where the section really is a question, as in an FAQ.

Text people scan

Paragraphs and line length

Put the conclusion in the first sentence and the reason after it, so a reader who stops there still has the answer. One idea to a paragraph, three or four lines on screen at most.

  • Sentences under 20 words, and never over 30.
  • A line of running text runs 45–75 characters. The hard limit is 80, from WCAG 1.4.8.
  • Hold that limit with the --i80-layout-measure token on the text container, never by breaking lines by hand. The Code tab shows where it goes.

Lists, tables or prose

Prose explains why, a list is made to be scanned, and a table is for things compared on the same attributes. Picking the wrong one is the most common reason a correct page still reads badly.

Use When
Prose Explaining why, or following a line of reasoning
Bulleted list Three to seven parallel items
Numbered list Steps that have to be taken in order
Table Items compared on the same attributes
Accordion Content most people never need
  • Items in a list start the same way: all verbs, or all nouns.
  • No full stop after a fragment.
  • Put a sentence between two lists, or between two alerts. Never stack them.
  • One level of nesting, at most.

UI text and voice

Microcopy is the label, the button, the error and the empty state: the few words that decide whether someone finishes the task. Say what happens, in the order the reader needs it.

  • Buttons and links: verb plus object — "Save plan", "Delete shift". Never "Click here", never "Submit", and never "OK" on something destructive. Button has the length limits.
  • Errors: what happened, then what to do. "The plan could not be saved. Check your connection and try again." Never blame the reader. A whole screen that failed is an application state.
  • Empty states: what will appear here, and the action that puts it there.
  • Confirmations: name the object and the consequence. "Delete 'Week 42'? This cannot be undone."
  • Labels: a noun, visible, above the field. A placeholder is never a label — see Form primitives.

Voice and tone and Writing style set the voice for all of this: "you" for the reader, "we" for the organisation behind the product, active voice, present tense, plain words. Two more rules belong here rather than there.

  • One language to a page. Danish interface text does not get English headings, and the other way round.
  • Danish is plain Danish: short words, "du" in lowercase, "kontakt os" rather than officialese. Product and component names are never translated.

Never write "above" or "below", and never point at a place on the screen. Link to the section instead, so the text survives a change of layout and still reads correctly aloud.

Accessibility and compliance

The rules on this page are WCAG 2.2 AA, which is the bar EN 301 549 sets. That standard carries into the Danish web accessibility law for the public sector, and into the European Accessibility Act, in force for many private products since June 2025.

Rule on this page WCAG
One h1, no skipped levels, an explicit title-tag 1.3.1 Info and relationships
The page title says what the h1 says 2.4.2 Page titled
Headings and labels describe what follows them 2.4.6 Headings and labels
Every section has a heading 2.4.10 Section headings (AAA, adopted anyway)
At most 80 characters to a line 1.4.8 Visual presentation (AAA, adopted anyway)
Link text says where the link goes 2.4.4 Link purpose

Accessibility covers the rest of a page's structure: landmark roles, the page title on a route change, and accessible names.

Set the heading level

Components render their title in a div by default, so no component ever claims a place in your outline by accident. Set title-tag on the element that carries the title, at the level the outline asks for.

Accordion items

title-tag goes on each <i80-accordion-item>, not on the accordion around them. The accordion passes size and type down to its items; it does not pass this.

<h2>Billing</h2>
<i80-accordion>
  <i80-accordion-item title-tag="h3" heading="When am I charged?" open>
    On the first of the month, for the month before.
  </i80-accordion-item>
  <i80-accordion-item title-tag="h3" heading="Can I change the card?">
    Yes, under Billing settings.
  </i80-accordion-item>
</i80-accordion>

Page header and application state

Page header is the one component that renders an h1 by default, because a screen's name is that screen's h1. Set title-tag only when the header sits in a page that has its h1 somewhere else.

<i80-page-header title="Q3 plans"
  description="Everything the team is working on this quarter."></i80-page-header>

An application state fills the screen, so on a dedicated error or empty page its title is the h1. Inside a panel on a page that already has one, it is an h2 or lower.

<i80-application-state title="Page not found" error-code="404" title-tag="h1">
  <p>Check the address, or go back to your plans.</p>
  <i80-link-standalone slot="footer" href="/plans" icon="arrow-left">
    All plans
  </i80-link-standalone>
</i80-application-state>

Steps and code blocks

A stepper list and a stepper nav take one title-tag for all of their step titles. Give them the level below the heading of the section they sit in.

<h2>Release checklist</h2>
<i80-stepper-list label="Release checklist" title-tag="h3">
  <i80-stepper-step status="complete" title="Scope agreed"></i80-stepper-step>
  <i80-stepper-step status="processing" title="Review"></i80-stepper-step>
  <i80-stepper-step title="Launch" description="21 September"></i80-stepper-step>
</i80-stepper-list>

A code block puts its title in a p, which is right for a sample sitting inside a paragraph of prose. Raise it when the sample is a section of its own.

<i80-code-block title="Install the stylesheet" title-tag="h3"
  language="bash" value="npm i @i80/design-system-components"></i80-code-block>

Keep lines readable

--i80-layout-measure is 70ch: the width running text stops at. Put it on the container that holds paragraphs and lists, and leave tables, code blocks and component previews out of it — those need every pixel of the column.

.article__body > p,
.article__body > ul,
.article__body > ol,
.article__body > blockquote {
  max-width: var(--i80-layout-measure);
}

This site works the same way. The documentation body caps its paragraphs, lists and blockquotes at the token, while tables, code blocks, previews and the do-and-don't panels keep the full width.

Checks we plan to add

Rules nobody checks drift. Two checks are planned for this repository, and neither is in place yet.

  • Vale over the Markdown: sentence-case headings, a warning on sentences past 25 words, and a short list of words to avoid — "utilise", "in order to", "simply", "click here".
  • A heading-outline check over the built site: one h1 and no skipped levels, run from the Playwright suite that already covers these pages.

Both are meant to run as a Gitea Actions job, over this documentation and over any product built with i80. The first version warns and does not fail a build, so that a drifting page is visible before it is blocking.