<script lang="ts">
import * as TableOfContents from "kumo-svelte/components/table-of-contents";
const headings = ["Introduction", "Installation", "Usage", "API Reference", "Examples"];
</script>
<div class="min-w-48">
<TableOfContents.Root>
<TableOfContents.Title>On this page</TableOfContents.Title>
<TableOfContents.List>
{#each headings as heading}
<TableOfContents.Item active={heading === "Usage"} class="cursor-pointer">{heading}</TableOfContents.Item>
{/each}
</TableOfContents.List>
</TableOfContents.Root>
</div>
Import
import * as TableOfContents from "kumo-svelte/components/table-of-contents"; Usage
<script lang="ts">
import * as TableOfContents from "kumo-svelte/components/table-of-contents";
</script>
<TableOfContents.Root>
<TableOfContents.Title>On this page</TableOfContents.Title>
<TableOfContents.List>
<TableOfContents.Item href="#intro" active>Introduction</TableOfContents.Item>
<TableOfContents.Item href="#api">API Reference</TableOfContents.Item>
</TableOfContents.List>
</TableOfContents.Root> This component is purely presentational. All interaction logic — scroll tracking, IntersectionObserver, active state management — is left to the consumer.
Examples
Interactive
Click an item to set it as active. The consumer controls state via active and onclick.
<script lang="ts">
import * as TableOfContents from "kumo-svelte/components/table-of-contents";
const headings = ["Introduction", "Installation", "Usage", "API Reference", "Examples"];
let active = $state("Introduction");
</script>
<div class="min-w-48">
<TableOfContents.Root>
<TableOfContents.Title>On this page</TableOfContents.Title>
<TableOfContents.List>
{#each headings as heading}
<TableOfContents.Item active={heading === active} onclick={() => (active = heading)} class="cursor-pointer">
{heading}
</TableOfContents.Item>
{/each}
</TableOfContents.List>
</TableOfContents.Root>
</div>
No active item
When no item has active set, all items show the default subtle text style with a hover indicator.
<script lang="ts">
import * as TableOfContents from "kumo-svelte/components/table-of-contents";
const headings = ["Introduction", "Installation", "Usage", "API Reference", "Examples"];
</script>
<div class="min-w-48">
<TableOfContents.Root>
<TableOfContents.Title>On this page</TableOfContents.Title>
<TableOfContents.List>
{#each headings as heading}
<TableOfContents.Item class="cursor-pointer">{heading}</TableOfContents.Item>
{/each}
</TableOfContents.List>
</TableOfContents.Root>
</div>
Groups
Use TableOfContents.Group to organize items into labeled sections with indented children. Pass an href to make the group label a clickable link, or omit it for a plain non-interactive title.
<script lang="ts">
import * as TableOfContents from "kumo-svelte/components/table-of-contents";
</script>
<div class="min-w-48">
<span id="examples-demo" class="sr-only">Examples</span>
<span id="api-demo" class="sr-only">API</span>
<TableOfContents.Root>
<TableOfContents.Title>On this page</TableOfContents.Title>
<TableOfContents.List>
<TableOfContents.Item active class="cursor-pointer">Overview</TableOfContents.Item>
<TableOfContents.Group label="Examples" href="#examples-demo">
<TableOfContents.Item class="cursor-pointer">Basic example</TableOfContents.Item>
<TableOfContents.Item class="cursor-pointer">Advanced example</TableOfContents.Item>
</TableOfContents.Group>
<TableOfContents.Group label="Getting Started">
<TableOfContents.Item class="cursor-pointer">Installation</TableOfContents.Item>
<TableOfContents.Item class="cursor-pointer">Configuration</TableOfContents.Item>
</TableOfContents.Group>
<TableOfContents.Group label="API" href="#api-demo">
<TableOfContents.Item class="cursor-pointer">Props</TableOfContents.Item>
<TableOfContents.Item class="cursor-pointer">Events</TableOfContents.Item>
</TableOfContents.Group>
</TableOfContents.List>
</TableOfContents.Root>
</div>
Without title
The title sub-component is optional — use TableOfContents.List directly if you don’t need a heading.
<script lang="ts">
import * as TableOfContents from "kumo-svelte/components/table-of-contents";
const headings = ["Introduction", "Installation", "Usage"];
</script>
<div class="min-w-48">
<TableOfContents.Root>
<TableOfContents.List>
{#each headings as heading}
<TableOfContents.Item active={heading === "Introduction"} class="cursor-pointer">{heading}</TableOfContents.Item>
{/each}
</TableOfContents.List>
</TableOfContents.Root>
</div>
Custom element
Use the child snippet to swap the default anchor for a button, router link, or any element.
<script lang="ts">
import * as TableOfContents from "kumo-svelte/components/table-of-contents";
const headings = ["Introduction", "Installation", "Usage"];
let clicked = $state("");
</script>
<div class="min-w-48 space-y-3">
<TableOfContents.Root>
<TableOfContents.List>
{#each headings as heading}
<TableOfContents.Item active={heading === "Introduction"} onclick={() => (clicked = heading)}>
{#snippet child({ props })}
<button {...props} type="button" onclick={() => (clicked = heading)}><span class="block min-w-0 leading-5">{heading}</span></button>
{/snippet}
</TableOfContents.Item>
{/each}
</TableOfContents.List>
</TableOfContents.Root>
{#if clicked}<p class="text-xs text-kumo-subtle">Clicked: {clicked}</p>{/if}
</div>
API Reference
TableOfContents
| Prop | Type | Default |
|---|---|---|
| children | Snippet | — |
TableOfContents.Group
| Prop | Type | Default |
|---|---|---|
| active | boolean | false |
| children | Snippet | — |
| class | string | — |
| href | string | — |
| label* | string | — |
TableOfContents.Item
| Prop | Type | Default |
|---|---|---|
| active | boolean | false |
| child | Snippet<[{ props: Record<string, unknown> & { class: string } }]> | — |
| children | Snippet | — |
| class | string | — |
| onclick | (event: MouseEvent) => void | — |
TableOfContents.List
| Prop | Type | Default |
|---|---|---|
| children | Snippet | — |
| class | string | — |
TableOfContents.Title
| Prop | Type | Default |
|---|---|---|
| children | Snippet | — |
| class | string | — |
Custom Elements
Use child snippets for custom elements.