Svelte Component

Table of Contents

Allows you to quickly navigate the hierarchy of headings for the current page.

typescript
import { TableOfContents, tocCrawler } from '@skeletonlabs/skeleton';
Source Page Source

Demo

How It Works

Heading IDs

Each page heading requires a unique ID that acts as the scroll target for inner-page navigation.

html
<h2 class="h2" id="how-it-works">How it Works</h2>

Anchor Links

Each link within the Table of Contents then points to the matching target ID as shown below. Note the use of the #. When clicked, the browser will automatically scroll so that the targeted element is at the top of the visible screen.

html
<a href="#how-it-works">How It Works</a>

Custom Title

Customize the table of contents title by editing the default Slot content.

html
<TableOfContents>
	<h1>title here</h1>
</TableOfContents>

Settings

Automatic IDs

Set mode: generate to enable tocCrawler to automatically generate and set unique IDs for all headings that are descendants of the element the action is applied to.

html
<div use:tocCrawler={{ mode: 'generate' }}>

See the example below. Note this will not overwrite IDs you have set manually.

html
<!-- Before: -->
<h2 class="h2">Title One</h2>
<h2 class="h2" id="my-custom-id">Title Two</h2>

<!-- After: -->
<h2 class="h2" id="title-one">Title One</h2>
<h2 class="h2" id="my-custom-id">Title Two</h2>

Prefixes and Suffixes

We recommend setting a custom heading (per the instruction above) if a conflict is found within your page. However, you may also hardcode a prefix or suffix to all generated IDs as follows:

html
<div use:tocCrawler={{ mode: 'generate', prefix: 'foo', suffix: 'bar' }}>

<!-- Ex: foo-title-one-bar -->
<!-- Ex: foo-title-two-bar -->

Ignore Headings

To ignore a heading in the target region, append a data-toc-ignore attribute. The crawler will skip this.

html
<h2 class="h2" data-toc-ignore>Ignore Me</h2>

Invisible Headings

Use the Tailwind-provided Screen Reader .sr-only class to append an invisible heading.

html
<h2 class="sr-only">Include Me!</h2>

Keyed Updates

In some situations you may want to force the crawler action to update on demand. Use the key parameter and pass a value that will be modified, which operates similar to Svelte's key blocks. This can be useful for scanning for new page headers for tabbed content.

typescript
let tabIndex = 0;

// Modifying this value triggers the crawler to run again:
// tabindex = 1;
html
<div use:tocCrawler={{ key: tabIndex }}>

Active on Scroll

The tocCrawler action can automatically select the top visible heading when you supply a scrollTarget element. That is the element that handles scrolling for the page. By default, this is set to target the body element. When using the Skeleton App Shell, designate scrollTarget: '#page' element as shown below. To disable this feature, set scrollTarget: ''.

NOTE: depending on your page layout, the page may not scroll low enough to activate the final links in the list.
html
<div use:tocCrawler={{ scrollTarget: '#page' }}>

Dynamic Headings

Generating links constructed using dynamic heading text may result in unexpected behavior.

html
<h2 class="h2">Greetings {name}</h2>

Svelte will compile and treat this as two seperate DOM elements, only the first of which is included in the generated link.

html
<!-- DOM -->
<h2 class="h2" id="greetings">
	"Greetings "
	"skeleton"
</h2>
html
<!-- Generated Link -->
<a href="#greetings">Greetings</a>

Solution

Use string interpolation to resolve this issue.

html
<h2 class="h2">{`Greetings ${name}`}</h2>

The component will be compiled as follows.

html
<!-- DOM -->
<h2 class="h2" id="greetings-skeleton">"Greetings Skeleton"</h2>
html
<!-- Generated Link -->
<a href="#greetings-skeleton">Greetings Skeleton</a>

Styling

Smooth Scrolling

Use Tailwind's scroll behavior styles to enable smooth scrolling on the scrollable element.

Make considerations for the Reduced Motion settings for proper accessibility.
html
<!-- If using the App Shell: -->
<AppShell regionPage="scroll-smooth"></AppShell>

<!-- If NOT using the App Shell: -->
<body class="scroll-smooth"></body>

Scroll Margin

Use Tailwind's scroll margin styles if you need to offset for sticky headers

NOTE: not currently supported for Skeleton's App Shell.
html
<body class="scroll-mt-[100px]"></body>

Sticky Positioning

Use Tailwind's sticky positioning styles to keep the Table of Contents component visible while scrolling.

html
<TableOfContents class="sticky top-10" />