
Research
/Security News
DuckDB npm Account Compromised in Continuing Supply Chain Attack
Ongoing npm supply chain attack spreads to DuckDB: multiple packages compromised with the same wallet-drainer malware.
astro-toc-generator
Advanced tools
Table of Contents generator for Astro.js with Sanity integration
A table of contents generator for Astro.js that works specifically with Sanity CMS blog content. This component automatically generates a table of contents from your Sanity portable text content, with support for custom styling and smooth scrolling.
npm install astro-toc-generator
---
import { TableOfContents, generateSlug } from 'astro-toc-generator';
import 'astro-toc-generator/styles'; // Import base styles
// Your Sanity portable text content
const content = [
{
_type: 'block',
style: 'h1',
children: [{ _type: 'span', text: 'Welcome to My Blog' }]
},
// ... more content blocks
];
---
<div class="layout">
<aside>
<TableOfContents
content={body?.value}
maxLevel={3}
containerClass="toc-container"
smoothScroll={true}
activeClass="active"
linkClass="toc-link"
listClass="toc-list"
listItemClass="toc-item"
headingSelector="h1, h2, h3"
/>
</aside>
<article>
<!-- Important: Add matching IDs to your headings using generateSlug -->
<h1 id={generateSlug('Welcome to My Blog')}>Welcome to My Blog</h1>
<h2 id={generateSlug('Introduction')}>Introduction</h2>
<!-- ... more content -->
</article>
</div>
:root {
/* Basic setup */
scroll-behavior: smooth;
/* Customize TOC appearance */
--toc-bg: #f8f9fa;
--toc-text-color: #666;
--toc-border-color: #eaeaea;
--toc-active-color: #0d6efd;
--toc-active-bg: rgba(13, 110, 253, 0.05);
--toc-hover-color: #000;
--toc-hover-bg: rgba(0, 0, 0, 0.05);
--toc-indent-size: 1rem;
--toc-border-radius: 8px;
--toc-transition: all 0.2s ease;
}
/* Layout setup */
.layout {
display: grid;
grid-template-columns: 3fr 1fr;
gap: 2rem;
}
aside {
position: sticky;
top: 0;
align-self: start;
height: 100vh;
overflow-y: auto;
padding-top: 2rem;
}
/* Add scroll margin to headings */
h1,
h2,
h3,
h4,
h5,
h6 {
scroll-margin-top: 2rem;
padding-top: 2rem;
}
/* Optional: Add box shadow to TOC */
.toc-container {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* Optional: Override specific styles */
.toc-link.active {
color: red; /* Change active color */
}
generateSlug
function:root
scroll-behavior: smooth
to your root elementscroll-margin-top
to headings for proper positioningProp | Type | Default | Description |
---|---|---|---|
content | PortableTextBlock[] or any[] | required | Your Sanity portable text content |
containerClass | string | 'toc-container' | Class for the container element |
listClass | string | 'toc-list' | Class for the list element |
listItemClass | string | 'toc-item' | Class for list items |
linkClass | string | 'toc-link' | Class for links |
activeClass | string | 'active' | Class for active links |
smoothScroll | boolean | true | Enable/disable smooth scrolling |
maxLevel | number | 6 | Maximum heading level to include (1-6) |
headingSelector | string | 'h1, h2, h3, h4, h5, h6' | Selector for headings to track |
The component automatically maps Sanity heading styles to their corresponding HTML levels:
Sanity Style | HTML Level | Description |
---|---|---|
h1 | Level 1 | Main title/chapter heading |
h2 | Level 2 | Section heading |
h3 | Level 3 | Subsection heading |
h4 | Level 4 | Sub-subsection heading |
h5 | Level 5 | Minor heading |
h6 | Level 6 | Smallest heading |
Each TOC item receives classes based on its heading level for targeted styling:
/* Target specific heading levels */
.toc-item.level-1 {
/* h1 headings */
}
.toc-item.level-2 {
/* h2 headings */
}
.toc-item.level-3 {
/* h3 headings */
}
.toc-item.level-4 {
/* h4 headings */
}
.toc-item.level-5 {
/* h5 headings */
}
.toc-item.level-6 {
/* h6 headings */
}
/* Example: Style different levels differently */
.toc-item.level-1 .toc-link {
font-weight: bold;
font-size: 1.1em;
}
.toc-item.level-2 .toc-link {
font-weight: 600;
}
.toc-item.level-3 .toc-link {
font-weight: normal;
opacity: 0.8;
}
The component also provides depth classes for nested items:
/* Target by nesting depth */
.toc-item.depth-0 {
/* Root level items */
}
.toc-item.depth-1 {
/* First level nested items */
}
.toc-item.depth-2 {
/* Second level nested items */
}
/* Example: Increase indentation per depth level */
.toc-item.depth-1 {
padding-left: calc(var(--toc-indent-size) * 1);
}
.toc-item.depth-2 {
padding-left: calc(var(--toc-indent-size) * 2);
}
Variable | Default | Description |
---|---|---|
--toc-bg | #f8f9fa | Background color of the TOC |
--toc-text-color | #666 | Default text color |
--toc-border-color | #eaeaea | Border color |
--toc-active-color | #0d6efd | Color for active items |
--toc-active-bg | rgba(13, 110, 253, 0.05) | Background for active items |
--toc-hover-color | #000 | Text color on hover |
--toc-hover-bg | rgba(0, 0, 0, 0.05) | Background on hover |
--toc-indent-size | 1rem | Indentation size for nested items |
--toc-border-radius | 8px | Border radius of the container |
--toc-transition | all 0.2s ease | Transition for hover/active states |
import { generateSlug } from "astro-toc-generator";
// Generate URL-friendly slugs for heading IDs
const slug = generateSlug("Your Heading Text");
/* Main headings (h1) - larger and bold */
.toc-item.level-1 .toc-link {
font-size: 1.2em;
font-weight: bold;
color: #000;
}
/* Subheadings (h2) - medium weight */
.toc-item.level-2 .toc-link {
font-size: 1.1em;
font-weight: 600;
color: #333;
}
/* Minor headings (h3+) - lighter */
.toc-item.level-3 .toc-link,
.toc-item.level-4 .toc-link,
.toc-item.level-5 .toc-link,
.toc-item.level-6 .toc-link {
font-size: 1em;
font-weight: normal;
color: #666;
}
.toc-item.level-2 {
padding-left: 1rem;
}
.toc-item.level-3 {
padding-left: 2rem;
}
.toc-item.level-4 {
padding-left: 3rem;
}
.toc-item.level-5 {
padding-left: 4rem;
}
.toc-item.level-6 {
padding-left: 5rem;
}
:root {
--toc-active-color: red;
--toc-active-bg: rgba(255, 0, 0, 0.05);
}
:root {
--toc-indent-size: 1.5rem;
}
:root {
--toc-bg: #fff;
--toc-border-radius: 12px;
}
.toc-container {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
:root {
--toc-hover-color: #0d6efd;
--toc-hover-bg: rgba(13, 110, 253, 0.1);
}
Here's how your Sanity content structure should look:
const content = [
// Level 1 - h1
{
_type: "block",
style: "h1",
children: [{ _type: "span", text: "Main Title" }],
},
// Level 2 - h2
{
_type: "block",
style: "h2",
children: [{ _type: "span", text: "Section Title" }],
},
// Level 3 - h3
{
_type: "block",
style: "h3",
children: [{ _type: "span", text: "Subsection Title" }],
},
];
npm create astro@latest -- --template minimal
Visit my portfolio at Bhargav Patel to explore my work, projects, and what I’ve been building lately.
MIT
FAQs
Table of Contents generator for Astro.js with Sanity integration
We found that astro-toc-generator demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
/Security News
Ongoing npm supply chain attack spreads to DuckDB: multiple packages compromised with the same wallet-drainer malware.
Security News
The MCP Steering Committee has launched the official MCP Registry in preview, a central hub for discovering and publishing MCP servers.
Product
Socket’s new Pull Request Stories give security teams clear visibility into dependency risks and outcomes across scanned pull requests.