Client component
Table of Contents
"On this page" navigation with scroll-spy: the entry whose heading is
currently on screen is highlighted, driven by IntersectionObserver — no
scroll handler. The entries are plain anchor links, so navigation works
before hydration and with JavaScript disabled; only the highlight is the
enhancement.
import { TableOfContents, ScrollArea, Box, Heading, Text, HStack } from "astralis-ui";
const SECTIONS = [
{ id: "toc-demo-intro", title: "Introduction" },
{ id: "toc-demo-install", title: "Installation" },
{ id: "toc-demo-theming", title: "Theming", depth: 1 },
{ id: "toc-demo-tokens", title: "Tokens", depth: 1 },
{ id: "toc-demo-faq", title: "FAQ" },
];
export function TableOfContentsDemo() {
return (
<HStack gap="8" alignItems="start" w="full" maxW="2xl">
<ScrollArea style={{ height: "14rem", flex: 1 }}>
{SECTIONS.map((s) => (
<Box key={s.id} pb="8">
<Heading as="h3" id={s.id} size="sm">
{s.title}
</Heading>
<Text size="sm" color="muted" mt="2">
Scroll this pane — the entry for the section under the header
highlights on the right. The links are plain anchors, so they
work before hydration too.
</Text>
</Box>
))}
</ScrollArea>
<TableOfContents items={SECTIONS} offset={0} style={{ width: "10rem", flexShrink: 0 }} />
</HStack>
);
}label
offset
import { TableOfContents } from "astralis-ui";
<TableOfContents
items={[
{ id: "import", title: "Import" },
{ id: "usage", title: "Usage" },
{ id: "props", title: "Props" },
{ id: "keyboard", title: "Keyboard" },
]}
/>
Import#
import { TableOfContents } from "astralis-ui";Usage#
Point items at heading ids that exist in the page:
<TableOfContents
items={[
{ id: "installation", title: "Installation" },
{ id: "theming", title: "Theming", depth: 1 },
{ id: "api", title: "API" },
]}
/>Props#
Extends nav props:
| Prop | Type | Default | Description |
|---|---|---|---|
items | { id: string; title: string; depth?: number }[] | — | The entries. Each id must match a heading's id on the page; depth indents it. Required. |
label | string | "On this page" | Accessible name of the nav, also shown as a title above the list. |
showLabel | boolean | true | Shows the label above the list. Hidden, it still names the nav. |
offset | number | 80 | Height of a sticky header, in pixels, so the entry highlights when its heading clears it. |
Keyboard#
The entries are plain links: Tab moves through them and Enter jumps to the
heading. The highlight follows the scroll position, not focus.