Rendering a Table of Contents (ToC)

Methanol automatically extracts headings during compilation and provides them as structured data via ctx.page.toc.

Each entry in the ToC follows this structure:

{
	depth: 2,
	id: 'my-heading',
	value: 'My heading',
	children: []
}

ToC Renderer Implementation

A standard recursive implementation:

const Toc = ({ toc }) => {
	if (!toc || toc.length === 0) return null

	return (
		<nav aria-label="Table of Contents">
			<div>On this page</div>
			<ul>
				{toc.map((item) => (
					<li>
						<a href={`#${item.id}`}>{item.value}</a>
						{item.children?.length ? <Toc toc={item.children} /> : null}
					</li>
				))}
			</ul>
		</nav>
	)
}

export default function PageTemplate({ PageContent, ExtraHead, ctx }) {
	return (
		<>
			<html>
				<head>
					<ExtraHead />
				</head>
				<body>
					<main>
						<PageContent />
					</main>
					<aside>
						<Toc toc={ctx.page.toc} />
					</aside>
				</body>
			</html>
		</>
	)
}

Best Practices