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 }[] | None | 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.