jekyll-toc-generator
Hook-based table of contents injection for Jekyll. Posts and pages with toc: true in frontmatter automatically get a TOC injected — no Liquid tag required in the content.
Installation
Add to your Jekyll site's Gemfile:
gem "jekyll-toc-generator"
Then add to _config.yml:
plugins:
- jekyll-toc-generator
Run bundle install.
Usage
Add toc: true to any post or page frontmatter:
---
title: My Long Post
toc: true
---
The plugin automatically injects a <nav class="toc"> element immediately before the first <h2> in the rendered HTML. No Liquid tag needed.
Configuration
All options are optional. Add to _config.yml:
toc:
min_headings: 2 # don't inject TOC if fewer than N h2s (default: 2)
title: "Contents" # TOC nav title (default: "Table of Contents")
levels: [2, 3] # heading levels to include (default: [2, 3])
Options
| Option | Default | Description |
|---|---|---|
min_headings |
2 |
Minimum number of <h2> elements required to inject a TOC |
title |
"Table of Contents" |
Text shown in the TOC <h2> title |
levels |
[2, 3] |
Heading levels to include in the TOC |
TOC HTML Structure
<nav class="toc" aria-label="Table of contents">
<h2 class="toc__title">Table of Contents</h2>
<ul class="toc__list">
<li class="toc__item"><a href="#heading-slug">Heading Text</a>
<ul class="toc__sublist">
<li class="toc__item--sub"><a href="#sub-heading-slug">Sub Heading</a></li>
</ul>
</li>
</ul>
</nav>
CSS Classes
| Class | Element | Description |
|---|---|---|
.toc |
<nav> |
Outer TOC container |
.toc__title |
<h2> |
TOC section title |
.toc__list |
<ul> |
Top-level heading list |
.toc__item |
<li> |
Top-level heading item |
.toc__sublist |
<ul> |
Nested subheading list |
.toc__item--sub |
<li> |
Subheading item |
Example CSS
.toc {
background: #f8f8f8;
border: 1px solid #ddd;
border-radius: 4px;
padding: 1rem 1.5rem;
margin-bottom: 2rem;
display: inline-block;
min-width: 200px;
}
.toc__title {
font-size: 1rem;
margin: 0 0 0.5rem;
font-weight: 600;
}
.toc__list,
.toc__sublist {
list-style: none;
margin: 0;
padding: 0;
}
.toc__sublist {
padding-left: 1rem;
}
.toc__item,
.toc__item--sub {
margin: 0.25rem 0;
}
Slug Generation
Heading IDs are slugified to match Jekyll's default anchor generation:
- Lowercase
- Non-alphanumeric characters removed
- Spaces and underscores replaced with
- - Leading/trailing hyphens stripped
Example: "What's New?" → #whats-new
Requirements
- Jekyll >= 4.0
- Ruby >= 2.7
- No additional gem dependencies (pure Ruby, no Nokogiri)
License
MIT © Jason Chance 2025