Overview
The Table of Contents plugin automatically generates a table of contents based on heading blocks in your document. It provides navigation links to headings and updates dynamically as content changes.
Installation
npm install @yoopta/table-of-contents
Basic Usage
import { useMemo } from 'react' ;
import YooptaEditor , { createYooptaEditor } from '@yoopta/editor' ;
import TableOfContents from '@yoopta/table-of-contents' ;
import { HeadingOne , HeadingTwo , HeadingThree } from '@yoopta/headings' ;
const plugins = [ HeadingOne , HeadingTwo , HeadingThree , TableOfContents ];
export default function Editor () {
const editor = useMemo (() => createYooptaEditor ({ plugins , marks: [] }), []);
return < YooptaEditor editor = { editor } onChange = { () => {} } /> ;
}
Features
Auto-Generation : Automatically extracts headings from document
Multi-Level : Support for H1, H2, H3 (configurable depth)
Live Updates : Updates in real-time as headings change
Navigation : Click to scroll to heading
Numbered Lists : Optional numbering (1. 2. 3.)
Collapsible : Optional collapsible TOC block
Custom Title : Set custom title (e.g., “Contents”, “On this page”)
Shortcuts : Type toc or table-of-contents to insert
Configuration
import TableOfContents from '@yoopta/table-of-contents' ;
const plugins = [ TableOfContents ];
Options
title
string
default: "Table of Contents"
Display title in UI menus
description
string
default: "Insert table of contents"
Description shown in menus
shortcuts
string[]
default: "['toc', 'table-of-contents']"
Keyboard shortcuts to trigger the plugin in slash menu
Element Props
Maximum heading level to show
1 - Only H1
2 - H1 and H2
3 - H1, H2, and H3
Optional title displayed above the TOC (e.g., “Table of Contents”, “On this page”)
headingTypes
string[]
default: "['HeadingOne', 'HeadingTwo', 'HeadingThree']"
Block types to treat as headings
Show numbered list (1. 2. 3.)
Allow collapsing the TOC block
Commands
Table of Contents commands are available via TableOfContentsCommands.
insertTableOfContents
Insert a new Table of Contents block.
import TableOfContents , { TableOfContentsCommands } from '@yoopta/table-of-contents' ;
TableOfContentsCommands . insertTableOfContents ( editor , {
props: {
depth: 2 ,
title: 'On this page' ,
showNumbers: true ,
headingTypes: [ 'HeadingOne' , 'HeadingTwo' ],
collapsible: false ,
},
at: 0 ,
focus: false ,
});
Block types to include as headings
Index where to insert the block
Whether to focus after insert
updateTableOfContents
Update TOC properties.
import { TableOfContentsCommands } from '@yoopta/table-of-contents' ;
TableOfContentsCommands . updateTableOfContents ( editor , blockId , {
depth: 2 ,
showNumbers: true ,
});
deleteTableOfContents
Delete a TOC block.
import { TableOfContentsCommands } from '@yoopta/table-of-contents' ;
TableOfContentsCommands . deleteTableOfContents ( editor , blockId );
buildTableOfContentsElements
Build TOC element structure (used internally).
import { TableOfContentsCommands } from '@yoopta/table-of-contents' ;
const tocElement = TableOfContentsCommands . buildTableOfContentsElements ( editor , {
props: { depth: 2 },
});
Hooks
useTableOfContentsItems
Hook for accessing TOC items and building custom TOC UI.
import { useTableOfContentsItems } from '@yoopta/table-of-contents' ;
function CustomTOC ({ editor , blockId }) {
const { items , loading , scrollToHeading } = useTableOfContentsItems ( editor , {
blockId ,
depth: 2 ,
headingTypes: [ 'HeadingOne' , 'HeadingTwo' ],
});
return (
< nav >
< h3 > Contents </ h3 >
< ul >
{ items . map (( item ) => (
< li
key = {item. id }
style = {{ marginLeft : ` ${ item . level * 20 } px` }}
onClick = {() => scrollToHeading (item.id)}
>
{ item . text }
</ li >
))}
</ ul >
</ nav >
);
}
Hook Options :
Maximum heading level to include
Block types to treat as headings
Hook Return :
type UseTableOfContentsItemsReturn = {
items : TableOfContentsItem [];
loading : boolean ;
scrollToHeading : ( headingId : string ) => void ;
};
type TableOfContentsItem = {
id : string ;
text : string ;
level : number ; // 1, 2, or 3
blockId : string ;
};
Types & Constants
Heading Type Levels
import { HEADING_TYPE_LEVEL } from '@yoopta/table-of-contents' ;
// Maps heading block types to levels
HEADING_TYPE_LEVEL = {
HeadingOne: 1 ,
HeadingTwo: 2 ,
HeadingThree: 3 ,
};
Default Heading Types
import { DEFAULT_HEADING_TYPES } from '@yoopta/table-of-contents' ;
// Default heading types to include
DEFAULT_HEADING_TYPES = [ 'HeadingOne' , 'HeadingTwo' , 'HeadingThree' ];
Usage Examples
Basic TOC
TableOfContentsCommands . insertTableOfContents ( editor , {
props: {
depth: 3 ,
title: 'Table of Contents' ,
},
at: 0 ,
});
TOC with Numbers
TableOfContentsCommands . insertTableOfContents ( editor , {
props: {
depth: 2 ,
title: 'Contents' ,
showNumbers: true ,
},
at: 0 ,
});
Custom Heading Types
TableOfContentsCommands . insertTableOfContents ( editor , {
props: {
depth: 2 ,
headingTypes: [ 'CustomHeading1' , 'CustomHeading2' ],
title: 'Page Outline' ,
},
at: 0 ,
});
Collapsible TOC
TableOfContentsCommands . insertTableOfContents ( editor , {
props: {
depth: 3 ,
title: 'On this page' ,
collapsible: true ,
},
at: 0 ,
});
Parsers
HTML
Deserialize : <nav> or <div> with TOC structure
Serialize : TOC block → <nav> with nested list of heading links
Email
Serialize : Table-based layout with TOC links for email clients
Styling
The TOC plugin provides structure; you can style it with CSS:
/* Example TOC styles */
.toc-container {
padding : 20 px ;
background : #f8f9fa ;
border-radius : 8 px ;
}
.toc-title {
font-size : 18 px ;
font-weight : bold ;
margin-bottom : 12 px ;
}
.toc-list {
list-style : none ;
padding : 0 ;
}
.toc-item {
padding : 4 px 0 ;
cursor : pointer ;
}
.toc-item:hover {
color : #007bff ;
}
.toc-item.level-1 {
margin-left : 0 ;
}
.toc-item.level-2 {
margin-left : 20 px ;
}
.toc-item.level-3 {
margin-left : 40 px ;
}
Best Practices
Placement
Place TOC at the beginning of long documents:
// Insert at the start
TableOfContentsCommands . insertTableOfContents ( editor , {
at: 0 ,
props: { depth: 2 , title: 'Contents' },
});
Depth Selection
Use appropriate depth based on document structure:
Short articles : depth: 2 (H1, H2)
Documentation : depth: 3 (H1, H2, H3)
Landing pages : depth: 1 (H1 only)
Custom Headings
If you have custom heading plugins:
TableOfContentsCommands . insertTableOfContents ( editor , {
props: {
headingTypes: [ 'Title' , 'Subtitle' , 'Section' ],
},
});