Table of contents
Add a contents list with links and page numbers that update with your document.
A table of contents lists headings inside your document, with a link and page number for each entry. Format resolves page numbers after pagination, so they stay accurate as content moves between pages.
For navigation in the PDF viewer's sidebar, see Bookmarks.
Add a table of contents
Place a <TableOfContents> directly in a Flow, before the headings you want to list. Set collect to choose the heading levels:
<Document title="Student handbook" lang="en">
<Layout id="page" width={793.71} height={1122.52}>
<Flow>
<TableOfContents collect="h1, h2">
<h1>Contents</h1>
</TableOfContents>
<PageBreak />
<h1>Admissions</h1>
<h2>Entry requirements</h2>
<p>Who can apply, and when.</p>
<h1>Fees</h1>
<p>Tuition fees and payment dates.</p>
</Flow>
</Layout>
</Document><template>
<Document title="Student handbook" lang="en">
<Layout id="page" :width="793.71" :height="1122.52">
<Flow>
<TableOfContents collect="h1, h2">
<h1>Contents</h1>
</TableOfContents>
<PageBreak />
<h1>Admissions</h1>
<h2>Entry requirements</h2>
<p>Who can apply, and when.</p>
<h1>Fees</h1>
<p>Tuition fees and payment dates.</p>
</Flow>
</Layout>
</Document>
</template><template data-type="document" data-title="Student handbook" data-lang="en">
<template data-type="layout" data-id="page" data-width="793.71px" data-height="1122.52px">
<template data-type="flow">
<template data-type="toc" data-collect="h1, h2">
<h1>Contents</h1>
</template>
<template data-type="page-break"></template>
<h1>Admissions</h1>
<h2>Entry requirements</h2>
<p>Who can apply, and when.</p>
<h1>Fees</h1>
<p>Tuition fees and payment dates.</p>
</template>
</template>
</template>The "Contents" heading appears above the entries and is not included in the list. <PageBreak> starts the body on a new page.
In a scaffolded Flow, place the table of contents directly inside the Stream. Wrapping it in other content, such as a <section>, prevents it from rendering.
Include heading numbers
A table of contents works without numbered headings. If you add <Numbering> to the Document, entries also show their headings' section numbers.
Add a title or introduction
Put content that introduces the list inside TableOfContents: a "Contents" heading, a short explanation, or column labels. Format displays it above the generated entries. Headings inside the element are excluded from numbering and from every table of contents, including earlier lists.
<TableOfContents collect="h1, h2">
<h1>Contents</h1>
<p>Find admission requirements, fees, and payment dates.</p>
</TableOfContents><TableOfContents collect="h1, h2">
<h1>Contents</h1>
<p>Find admission requirements, fees, and payment dates.</p>
</TableOfContents><template data-type="toc" data-collect="h1, h2">
<h1>Contents</h1>
<p>Find admission requirements, fees, and payment dates.</p>
</template>Put a chapter title or introduction before the element when it belongs to the document's body. A heading there can be numbered and collected by an earlier contents list. It won't appear in its own chapter list, which only collects headings that follow it.
Place the sections you want to list after the TableOfContents element. Content inside it introduces the list.
Content inside the element appears once by default. Set repeatHead to repeat it on each contents page. Content placed before the element isn't repeated by this setting.
Choose headings
The default collect selector is h1, h2, h3. Use collect="h1" to list chapters only, or collect="h2, h3" for sections and subsections.
Each list collects matching headings in document order, starting after its own position. Collection continues across Flows and Layouts, so a contents page can list chapters in later Layouts. Headings before the list are excluded.
Selectors match flowing content, excluding surrounding scaffolding. For example, if a <main> wraps the Flow, select h2, not main h2.
To exclude a heading from a particular list, narrow its collect selector. For example, collect="h1:not(.omit-from-contents), h2:not(.omit-from-contents)" skips headings with that class. Headings marked data-unnumbered are excluded from all tables of contents and from heading numbering.
Use multiple tables of contents
Add a table of contents before each part of a document to give each part its own list. With the default settings, each list stops where the next one begins. The last list continues to the end of the document.
<Flow>
<TableOfContents collect="h1">
<h2>Handbook contents</h2>
</TableOfContents>
<h1>Admissions</h1>
<p>Entry requirements and how to apply.</p>
<h1>Fees</h1>
<p>Tuition fees and payment dates.</p>
<PageBreak />
<TableOfContents collect="h1">
<h2>Course contents</h2>
</TableOfContents>
<h1>Accounting</h1>
<p>Accounting courses and prerequisites.</p>
<h1>Biology</h1>
<p>Biology courses and prerequisites.</p>
</Flow><Flow>
<TableOfContents collect="h1">
<h2>Handbook contents</h2>
</TableOfContents>
<h1>Admissions</h1>
<p>Entry requirements and how to apply.</p>
<h1>Fees</h1>
<p>Tuition fees and payment dates.</p>
<PageBreak />
<TableOfContents collect="h1">
<h2>Course contents</h2>
</TableOfContents>
<h1>Accounting</h1>
<p>Accounting courses and prerequisites.</p>
<h1>Biology</h1>
<p>Biology courses and prerequisites.</p>
</Flow><template data-type="flow">
<template data-type="toc" data-collect="h1">
<h2>Handbook contents</h2>
</template>
<h1>Admissions</h1>
<p>Entry requirements and how to apply.</p>
<h1>Fees</h1>
<p>Tuition fees and payment dates.</p>
<template data-type="page-break"></template>
<template data-type="toc" data-collect="h1">
<h2>Course contents</h2>
</template>
<h1>Accounting</h1>
<p>Accounting courses and prerequisites.</p>
<h1>Biology</h1>
<p>Biology courses and prerequisites.</p>
</template>The first list contains Admissions and Fees. The second contains Accounting and Biology. Each looks forward from its own position. Neither lists the whole document.
This rule also applies when the lists use different collect selectors. With these settings, two lists placed together leave the first empty because no headings fall between them.
Add chapter contents
Use within to choose a heading that ends the list. For chapter contents, place the list after its chapter heading and set within="h1". It stops before the next h1:
<Flow>
<TableOfContents collect="h1">
<h1>Contents</h1>
</TableOfContents>
<PageBreak />
<h1>Admissions</h1>
<TableOfContents collect="h2" within="h1" />
<h2>Entry requirements</h2>
<p>Who can apply, and when.</p>
<h2>How to apply</h2>
<p>Submit your application online.</p>
<h1>Fees</h1>
<h2>Payment dates</h2>
<p>Pay each instalment before the start of term.</p>
</Flow><Flow>
<TableOfContents collect="h1">
<h1>Contents</h1>
</TableOfContents>
<PageBreak />
<h1>Admissions</h1>
<TableOfContents collect="h2" within="h1" />
<h2>Entry requirements</h2>
<p>Who can apply, and when.</p>
<h2>How to apply</h2>
<p>Submit your application online.</p>
<h1>Fees</h1>
<h2>Payment dates</h2>
<p>Pay each instalment before the start of term.</p>
</Flow><template data-type="flow">
<template data-type="toc" data-collect="h1">
<h1>Contents</h1>
</template>
<template data-type="page-break"></template>
<h1>Admissions</h1>
<template data-type="toc" data-collect="h2" data-within="h1"></template>
<h2>Entry requirements</h2>
<p>Who can apply, and when.</p>
<h2>How to apply</h2>
<p>Submit your application online.</p>
<h1>Fees</h1>
<h2>Payment dates</h2>
<p>Pay each instalment before the start of term.</p>
</template>The main list includes Admissions and Fees. The chapter list includes Entry requirements and How to apply, and stops before Fees.
A list with within is independent of other tables of contents: it neither ends their lists nor stops at them. This lets each chapter have its own contents without interrupting the main list.
Use custom boundaries
Both collect and within accept CSS selectors. A catalog can use a main list, chapter lists, and a subject index, each with its own selection and stopping point:
| List | collect | within |
|---|---|---|
| Main contents | .part-title, .chapter-title | .reference-part |
| Chapter contents | h3 | .chapter-title |
| Subject index | .subject-name | .chapter-title |
The main list starts on the contents page and stops before the first heading with the reference-part class. Each chapter list starts after its chapter title and stops before the next one. The subject index starts before the subject headings in its chapter. These lists can sit in different Flows or Layouts.
within identifies the next heading that ends a list. It isn't a selector for a parent container. If no later heading matches, the list continues to the end of the document.
Style the entries
Use --toc-* CSS custom properties to adjust type size, indentation, spacing, and dot leaders. Add these rules to your Layout stylesheet:
[data-type="toc"] {
--toc-font-size: 16px;
--toc-page-number-font-size: 14px;
--toc-depth-indent-step: 1.25em;
--toc-space-before-root: 0.8em;
--toc-leader-color: #999;
}
[data-type="toc-entry"][data-depth="0"] [data-type="toc-title"] {
font-weight: 600;
}Entries follow the heading hierarchy. The shallowest heading level has data-depth="0", so a list of only h2 headings starts at depth 0. The rule above makes those top-level titles bold.
Dot leaders connect titles to page numbers by default. Set leader="none" to leave the space blank:
<TableOfContents collect="h1, h2" leader="none" /><TableOfContents collect="h1, h2" leader="none" /><template data-type="toc" data-collect="h1, h2" data-leader="none"></template>See the DOM contract for all styling attributes and custom properties.
Add descriptions
Set data-toc-description on a heading to add a description below its contents entry:
<h1 data-toc-description="Tuition fees, payment dates, and financial support.">Fees</h1><h1 data-toc-description="Tuition fees, payment dates, and financial support.">Fees</h1><h1 data-toc-description="Tuition fees, payment dates, and financial support.">Fees</h1>The description appears in the table of contents without changing the heading on the page.
Continue across pages
Long lists continue onto new pages, breaking between entries. Page numbers account for the space the contents list occupies.
By default, content inside TableOfContents appears once above the entries. Set repeatHead to repeat all of it on every contents page. This is useful for a short title or column labels:
<TableOfContents collect="h1, h2" repeatHead>
<h1>Contents</h1>
</TableOfContents><TableOfContents collect="h1, h2" repeat-head>
<h1>Contents</h1>
</TableOfContents><template data-type="toc" data-collect="h1, h2" data-repeat-head="true">
<h1>Contents</h1>
</template>Keep any introduction that should appear only once before the element, and put only the content you want repeated inside it.