Table-of-Contents Generator for Jekyll Posts

comments

For now, I'm using redcarpet as markdown preprocessor for this blog. Last week I started to write long post with many headers and wanted to add a table of contents. It seems like kramdown preprocessor supports it out of the box, but redcarpet isn't. In this post I'll show the solution.

There is many javascript-based hand-made solutions for redcarpet based on with_toc_data extension (example). They usually works in browser but I'd like to have a solution which will generate HTML table of contents during jekyll build command.

I found that redcarpet already supports TOC generation using Redcarpet::Render::HTML_TOC renderer, but there is no such support in jekyll. There are several issues on Github dedicated to table of contents generation in jekyll. All of them was closed with message won't be implemented because it can be done with current API. This last comment with broken draft implementation pushed me to find solution on my own.

Generator

Because of Redcarpet::Render::HTML_TOC renderer works with plain markdown input only, we need to write a Jekyll's Generator. Generator'll run before the site is generated. I wrote simple generator:

require 'redcarpet'

module Jekyll
  class TocGenerator < Generator
    safe true

    def generate(site)
      toc_render = Redcarpet::Render::HTML_TOC.new(nesting_level: 3)
      parser     = Redcarpet::Markdown.new(toc_render, fenced_code_blocks: true)
      site.posts.docs
        .find_all {|post| post.content.include?('{:toc}')}
        .each do |post|
          toc = parser.render(post.content)
          post.content.gsub! '{:toc}', toc
        end
    end
  end
end

You can put this toc_generator.rb file into _plugins folder of your jekyll-based blog.

With this generator in place you can write {:toc} tag in your posts and it will be replaced with actual table of contents according to headings. If you wants to disable table of contents generation for specific post, just set noToc: true in post's YAML front matter.

Happy writing!

Comments