Overview
Preview state
Documentation article
Supply already-discovered headings from your app, then let PageToc render the aside and active-link treatment.
App owns
Markdown parsing, route paths, and page layout.
Component owns
Link list rendering, indentation, and active state display.
Installation
pnpm dlx shadcn-vue@latest add "https://ui.stackhacker.io/r/page-toc.json"
Usage
<script setup lang="ts">
import { PageToc, type PageTocItem } from "@/components/page-toc";
const headings: PageTocItem[] = [
{ id: "overview", title: "Overview", depth: 2 },
{ id: "installation", title: "Installation", depth: 2 },
{ id: "usage", title: "Usage", depth: 2 },
{ id: "examples", title: "Examples", depth: 3 },
];
</script>
<template>
<PageToc :items="headings" class="sticky top-6" />
</template>href defaults to #${id}. Pass a full path when your page shell needs route-aware anchors.
const headings: PageTocItem[] = [
{ id: "installation", title: "Installation", href: "/docs/components/page-toc#installation" },
];App-Owned Headings
PageToc owns the visual table-of-contents list and active-link behavior for the data you pass in. Your app owns markdown parsing, heading extraction, page layout, and current route handling.
For Nuxt Content, map page.body.toc.links or another app-level source into PageTocItem[] before rendering the component.
import type { PageTocItem } from "@/components/page-toc";
const headings: PageTocItem[] = page.body.toc.links.flatMap(link => [
{
id: link.id,
title: link.text,
depth: link.depth,
},
...(link.children ?? []).map(child => ({
id: child.id,
title: child.text,
depth: child.depth,
})),
]);The component intentionally does not import Nuxt Content types, query content collections, inspect the current route, or create the page's aside column.
Active State
By default, PageToc observes matching heading elements by id in the browser and highlights the active link.
Use controlled active state when your page already knows the active heading, or when rendering a static preview.
<PageToc
:items="headings"
active-id="installation"
:track-active="false"
/>Examples
Default
Preview state
Documentation article
Supply already-discovered headings from your app, then let PageToc render the aside and active-link treatment.
App owns
Markdown parsing, route paths, and page layout.
Component owns
Link list rendering, indentation, and active state display.
API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | PageTocItem[] | [] | Heading links supplied by your app. |
title | string | "On this page" | Label rendered above the links. Use an empty string to hide it. |
trackActive | boolean | true | Observe matching page headings and update the active link. |
activeId | string | — | Controlled active heading id. Disables internal active tracking when supplied. |
class | HTMLAttributes["class"] | — | Additional CSS classes for the root nav. |
Types
interface PageTocItem {
id: string;
title: string;
href?: string;
depth?: number;
}
