Table of contents
A Table of contents lists the sections of a page. Its title stands above the links, each link on a one-square row. Nested sections stand one square further in. The section in view is marked in blue; the other links use the muted ink. Its width is twelve squares by default and stays within its container.
A long label fades out over its last square, never an ellipsis, and shows its full words in the shared tooltip on hover or keyboard focus.
Try it
Section titled “Try it”Follow the links or scroll the reading area. The current section updates in its own scroll container.
<style>
.toc-example { display:grid; grid-template-columns:calc(12 * var(--ds-unit)) minmax(0,1fr); gap:var(--ds-unit); width:100%; }
.toc-reading { height:calc(14 * var(--ds-unit)); overflow-y:auto; min-width:0; }
.toc-reading section { display:grid; gap:var(--ds-unit); padding:var(--ds-unit); min-height:calc(10 * var(--ds-unit)); box-sizing:border-box; }
@media(max-width:600px) { .toc-example { grid-template-columns:minmax(0,1fr); } }
</style>
<div class="toc-example">
<ds-table-of-contents label="On this page" literal>
<a href="#toc-overview">Overview</a>
<a href="#toc-design">Design examples</a>
<a href="#toc-try">Try it</a>
<a href="#toc-size" data-depth="1">Choose a size</a>
</ds-table-of-contents>
<article class="toc-reading" tabindex="0" aria-label="Example article">
<section><ds-text literal strong role="heading" aria-level="2" id="toc-overview">Overview</ds-text><ds-text literal wrap>A table of contents gives a longer page a clear structure. Each link takes you to a section.</ds-text></section>
<section><ds-text literal strong role="heading" aria-level="2" id="toc-design">Design examples</ds-text><ds-text literal wrap>Use it beside a guide, a reference or a long article. The page chooses where the contents stand.</ds-text></section>
<section><ds-text literal strong role="heading" aria-level="2" id="toc-try">Try it</ds-text><ds-text literal wrap>Scroll this article or follow a link. The current section is marked in the contents.</ds-text></section>
<section><ds-text literal strong role="heading" aria-level="3" id="toc-size">Choose a size</ds-text><ds-text literal wrap>Nested sections stand one square further in. The rows, words and gaps follow the surface scale.</ds-text></section>
</article>
</div> Use it
Section titled “Use it”Slot native links into <ds-table-of-contents>. Give a nested link data-depth="1" (or another nonnegative depth). Each same-page fragment names an element with that id. Keep the element and its targets in the same document or shadow root.
<ds-table-of-contents label="On this page" literal> <a href="#overview">Overview</a> <a href="#examples">Design examples</a> <a href="#try-it">Try it</a> <a href="#size" data-depth="1">Choose a size</a></ds-table-of-contents>You can instead set items to { href, label, depth? }[]. The label is a translation key by default (Contents); use literal for words that should appear as written. target can point to a content element when a composing component puts the contents in a separate shadow root. Call refresh() after replacing target elements without changing the links.
Navigation and current section
Section titled “Navigation and current section”Every entry is a real link and a Tab stop. Enter follows it and moves focus to the section. Modified clicks, links to other pages and downloads retain native browser behavior. Fragment navigation preserves the page query and creates a normal history entry.
The Unit tracks the nearest scrolling ancestor of its targets, including an independently scrolling article. It updates after scrolling or resizing, and marks the last visible section at the bottom. It reads geometry only when needed and removes listeners and observers when disconnected. toc-change reports { href } when the current section changes.
The Unit owns the links and current state. The page owns placement, sticky positioning and responsive visibility. The documentation uses it in the right sidebar; a full-width example page can leave it out.
React and customization
Section titled “React and customization”TableOfContents from react/table-of-contents.ts accepts items, label, literal, target and onSectionChange. Register the Lit element in the browser before hydration.
Use --ds-toc-width, --ds-toc-color and --ds-toc-current-color for a library-specific width or ink. Type, links, indentation and gaps follow the local --ds-sf scale. Light and dark colours come from the shared tokens.