Table of Contents
kumo-svelte
<script lang="ts">
  import { TableOfContents } from 'kumo-svelte';

  const headings = [
    'Introduction',
    'Installation',
    'Usage',
    'API Reference',
    'Examples'
  ];
</script>

<div class="min-w-48">
  <TableOfContents>
    <TableOfContents.Title>On this page</TableOfContents.Title>
    <TableOfContents.List>
      {#each headings as heading (heading)}
        <TableOfContents.Item active={heading === 'Usage'} class="cursor-pointer">
          {heading}
        </TableOfContents.Item>
      {/each}
    </TableOfContents.List>
  </TableOfContents>
</div>

Installation

Barrel

import { TableOfContents } from 'kumo-svelte';

Granular

import { TableOfContents } from 'kumo-svelte/components/table-of-contents';

Usage

<script lang="ts">import { TableOfContents } from "kumo-svelte";</script>    <TableOfContents>      <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>

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 { TableOfContents } from 'kumo-svelte';

  const headings = [
    'Introduction',
    'Installation',
    'Usage',
    'API Reference',
    'Examples'
  ];
  let active = $state('Introduction');
</script>

<div class="min-w-48">
  <TableOfContents>
    <TableOfContents.Title>On this page</TableOfContents.Title>
    <TableOfContents.List>
      {#each headings as heading (heading)}
        <TableOfContents.Item
          active={heading === active}
          onclick={() => (active = heading)}
          class="cursor-pointer"
        >
          {heading}
        </TableOfContents.Item>
      {/each}
    </TableOfContents.List>
  </TableOfContents>
</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 { TableOfContents } from 'kumo-svelte';

  const headings = [
    'Introduction',
    'Installation',
    'Usage',
    'API Reference',
    'Examples'
  ];
</script>

<div class="min-w-48">
  <TableOfContents>
    <TableOfContents.Title>On this page</TableOfContents.Title>
    <TableOfContents.List>
      {#each headings as heading (heading)}
        <TableOfContents.Item class="cursor-pointer">{heading}</TableOfContents.Item>
      {/each}
    </TableOfContents.List>
  </TableOfContents>
</div>

Groups

Use TableOfContents.Group to organize items into labeled sections with indented children. Groups support two modes: pass an href to make the group label a clickable link (like "Examples" and "API" below), or omit it for a plain non-interactive title (like "Getting Started").

<script lang="ts">
  import { TableOfContents } from 'kumo-svelte';
</script>

<div class="min-w-48">
  <TableOfContents>
    <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>
</div>

Without title

The title sub-component is optional — use TableOfContents.List directly if you don't need a heading.

<script lang="ts">
  import { TableOfContents } from 'kumo-svelte';

  const headings = [
    'Introduction',
    'Installation',
    'Usage',
    'API Reference',
    'Examples'
  ];
</script>

<div class="min-w-48">
  <TableOfContents>
    <TableOfContents.List>
      {#each headings.slice(0, 3) as heading (heading)}
        <TableOfContents.Item active={heading === 'Introduction'} class="cursor-pointer">
          {heading}
        </TableOfContents.Item>
      {/each}
    </TableOfContents.List>
  </TableOfContents>
</div>

Custom element

Use the render prop to swap the default anchor for a button, router link, or any element.

<script lang="ts">
  import { TableOfContents } from 'kumo-svelte';

  let clicked = $state<string | null>(null);
</script>

<div class="min-w-48 space-y-3">
  <TableOfContents>
    <TableOfContents.List>
      {#each ['Introduction', 'Installation', 'Usage'] as heading (heading)}
        <TableOfContents.Item
          as="button"
          type="button"
          active={heading === 'Introduction'}
          onclick={() => (clicked = heading)}
        >
          {heading}
        </TableOfContents.Item>
      {/each}
    </TableOfContents.List>
  </TableOfContents>
  {#if clicked}
    <p class="text-xs text-kumo-subtle">Clicked: {clicked}</p>
  {/if}
</div>

SvelteKit

<TableOfContents.Item render={<Link to="/intro" />} active>  Introduction</TableOfContents.Item>

Next.js

import Link from "next/link";<TableOfContents.Item render={<Link href="/intro" />} active>  Introduction</TableOfContents.Item>;

Button (no navigation)

<TableOfContents.Item render={<button type="button" />} onclick={handleClick}>  Introduction</TableOfContents.Item>

API Reference

TableOfContents

Root nav container with a default aria-label of "Table of contents".

PropTypeDefaultDescription
class string-Additional classes merged onto the nav element.
children Snippet-TableOfContents.Title and TableOfContents.List children.
aria-label string"Table of contents"Accessible label for the nav landmark.

TableOfContents.Title

Optional uppercase heading displayed above the list (renders a <p>).

PropTypeDefaultDescription
No component-specific props. Accepts standard HTML attributes.

TableOfContents.List

List container with a left border rail.

PropTypeDefaultDescription
No component-specific props. Accepts standard HTML attributes.

TableOfContents.Item

Individual navigation link. Set active for the current section. Use the render prop to swap the anchor for a router link or button.

PropTypeDefaultDescription
active booleanfalseWhether this item represents the currently active section.
href string-Destination URL.
as 'a' | 'button'"a"Svelte replacement for React's render prop when rendering a button item.

TableOfContents.Group

Groups items under a labeled section with indented children. Pass href to make the label a clickable link, or omit for a plain title.

PropTypeDefaultDescription
label *string-Label displayed above the group's items.
href string-URL the group label links to. When provided, the label renders as a clickable link.
active booleanfalseWhether this group's label represents the currently active section. Only applies when href is provided.