Core Plugins

Table of Contents

Plugin for automatically generating a table of contents from document headings.

The comark/plugins/toc plugin automatically generates a hierarchical table of contents (TOC) from document headings. The TOC is extracted from h2 through h6 elements and stored in the parse result's meta.toc property.

Basic Usage

The Table of Contents plugin is included in comark core package and available under comark/plugins/toc path.

Registering the Plugin

parse.ts
import { parse } from 'comark'
import toc from 'comark/plugins/toc'

const result = await parse(content, {
  plugins: [toc()]
})

console.log(result.meta.toc) // Generated table of contents

Default Configuration

By default, the plugin generates a TOC with these settings:

config.ts
{
  depth: 2,        // Include h2 and h3 headings
  searchDepth: 2   // Search 2 levels deep in nested structures
}

Configuration Options

depth

Controls which heading levels to include in the TOC:

config.ts
// Include only h2 and h3
toc({ depth: 2 })

// Include h2, h3, and h4
toc({ depth: 3 })

// Include h2, h3, h4, h5, and h6
toc({ depth: 5 })

Valid values: 1 to 5 (maps to heading levels h2-h6)

searchDepth

Controls how deep to search for headings in nested component structures:

config.ts
// Only search top-level headings
toc({ searchDepth: 1 })

// Search 2 levels deep (default)
toc({ searchDepth: 2 })

// Search 3 levels deep
toc({ searchDepth: 3 })

title

Set a custom title for the TOC:

config.ts
toc({ title: 'On This Page' })

Examples

Basic TOC Generation

import { parse } from 'comark'
import toc from 'comark/plugins/toc'

const content = `# Document Title

## Introduction

This is the introduction section.

## Features

### Performance
### Flexibility

## Conclusion
`

const result = await parse(content, {
  plugins: [toc()]
})

console.log(result.meta.toc)

Using Frontmatter to Control TOC

You can control TOC behavior via frontmatter:

parse.ts
const content = `---
title: My Article
depth: 3
searchDepth: 3
---

# My Article

## Section 1

### Subsection 1.1

#### Deep Heading

## Section 2
`

const result = await parse(content, {
  plugins: [toc()]
})

console.log(result.meta.toc.depth)       // 3 (from frontmatter)
console.log(result.meta.toc.title)       // "My Article" (from frontmatter)
console.log(result.meta.toc.searchDepth) // 3 (from frontmatter)

Vue TOC Component Example

DocsLayout.vue
<script setup lang="ts">
import { ref } from 'vue'
import { parse } from 'comark'
import { Comark } from '@comark/vue'
import toc from 'comark/plugins/toc'

const content = ref(`# Guide

## Introduction
## Installation
## Configuration
### Basic Setup
### Advanced Options
`)

const options = {
  plugins: [toc({ depth: 3 })]
}

// Parse to get TOC
const result = await parse(content.value, options)
const toc = result.meta.toc
</script>

<template>
  <div class="docs-layout">
    <!-- Sidebar with TOC -->
    <aside class="toc">
      <h2>{{ toc.title || 'Table of Contents' }}</h2>
      <nav>
        <ul>
          <li v-for="link in toc.links" :key="link.id">
            <a :href="`#${link.id}`">{{ link.text }}</a>
            <ul v-if="link.children">
              <li v-for="child in link.children" :key="child.id">
                <a :href="`#${child.id}`">{{ child.text }}</a>
              </li>
            </ul>
          </li>
        </ul>
      </nav>
    </aside>

    <!-- Main content -->
    <main>
      <Comark :options="options">{{ content }}</Comark>
    </main>
  </div>
</template>

React TOC Component Example

DocsPage.tsx
import { useState, useEffect } from 'react'
import { parse } from 'comark'
import { Comark } from '@comark/react'
import toc from 'comark/plugins/toc'

const content = `# Guide

## Introduction
## Installation
## Configuration
### Basic Setup
### Advanced Options
`

const options = {
  plugins: [toc({ depth: 3 })]
}

export default function DocsPage() {
  const [toc, setToc] = useState(null)

  useEffect(() => {
    async function loadToc() {
      const result = await parse(content, options)
      setToc(result.meta.toc)
    }
    loadToc()
  }, [])

  if (!toc) return <div>Loading...</div>

  return (
    <div className="docs-layout">
      {/* Sidebar with TOC */}
      <aside className="toc">
        <h2>{toc.title || 'Table of Contents'}</h2>
        <nav>
          <ul>
            {toc.links.map(link => (
              <li key={link.id}>
                <a href={`#${link.id}`}>{link.text}</a>
                {link.children && (
                  <ul>
                    {link.children.map(child => (
                      <li key={child.id}>
                        <a href={`#${child.id}`}>{child.text}</a>
                      </li>
                    ))}
                  </ul>
                )}
              </li>
            ))}
          </ul>
        </nav>
      </aside>

      {/* Main content */}
      <main>
        <Comark options={options}>{content}</Comark>
      </main>
    </div>
  )
}

Recursive TOC Renderer

For deeply nested TOCs:

TocRenderer.tsx
interface TocLinkProps {
  link: {
    id: string
    text: string
    children?: TocLinkProps['link'][]
  }
}

function TocLink({ link }: TocLinkProps) {
  return (
    <li>
      <a href={`#${link.id}`}>{link.text}</a>
      {link.children && (
        <ul>
          {link.children.map(child => (
            <TocLink key={child.id} link={child} />
          ))}
        </ul>
      )}
    </li>
  )
}

function TableOfContents({ toc }) {
  return (
    <nav>
      <ul>
        {toc.links.map(link => (
          <TocLink key={link.id} link={link} />
        ))}
      </ul>
    </nav>
  )
}

API Reference

toc(options?): ComarkPlugin

Creates a table of contents generation plugin.

Parameters:

  • options (optional) - TOC configuration options

Options:

types.ts
interface TocOptions {
  title?: string       // TOC title (default: '')
  depth?: number       // Heading depth to include: 1-5 (default: 2)
  searchDepth?: number // Search depth in nested structures (default: 2)
}

Returns: A Comark plugin that generates table of contents.

TOC Data Structure

types.ts
interface Toc {
  title: string         // TOC title
  depth: number         // Maximum heading depth included
  searchDepth: number   // Search depth in nested structures
  links: TocLink[]      // Hierarchical list of links
}

interface TocLink {
  id: string            // Heading ID (for anchor links)
  text: string          // Heading text content
  depth: number         // Heading level (2-6)
  children?: TocLink[]  // Nested child headings (optional)
}

Features

  • Automatic ID Generation: Headings automatically get IDs for anchor links
  • Hierarchical Structure: Nested headings create parent-child relationships
  • Frontmatter Integration: title, depth, and searchDepth can be set in frontmatter
  • Flexible Depth Control: Choose which heading levels to include
  • Search Depth: Control how deep to search in nested component structures
  • Text Extraction: Automatically extracts plain text from headings with formatting

Use Cases

  1. Documentation Sites - Generate navigation for long documentation pages
  2. Blog Posts - Create article outlines for reader navigation
  3. Guides & Tutorials - Help users navigate step-by-step instructions
  4. API Documentation - Organize method and property listings
  5. Landing Pages - Create "Jump to Section" navigation

How It Works

The plugin:

  1. Searches through the AST for heading elements (h2-h6)
  2. Extracts heading text, IDs, and depth information
  3. Organizes headings into a hierarchical structure
  4. Respects the depth setting to filter heading levels
  5. Uses searchDepth to determine how deep to search in nested structures
  6. Stores the result in tree.meta.toc

Notes

  • h1 headings are excluded from TOC (typically used for page title)
  • Headings must have an id attribute to appear in the TOC
  • The depth parameter maps to heading levels: 1 = h2 only, 2 = h2-h3, 3 = h2-h4, etc.
  • Frontmatter values override plugin options
  • The TOC is generated during parsing, not at render time
  • Works seamlessly with custom components and nested structures

See Also

Copyright © 2026