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>

Settings

Automatic IDs

Set mode: generate to enable tocCrawler to automatically generate and set unique IDs for all headings that are descendents 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. This operates similar to Svelte's key blocks.

typescript
const tabIndex = 0;
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 being 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' }}>

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 accessability.
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" />