JTFDI Library
just the focus do it    •    
Creator Economy
Eating & Drinking
Customer Relationships
•    just the focus do it    •     just the focus do it    
Try it for Free

An Extensive Dynamic Table of Contents Generator for Webflow CMS

, most recent update.

Table of Contents (ToC) Generator for Webflow CMS

Updated 2023 Version

I have done versions of this script in the past. This one is the most extensive with 4 different functionalities:

  1. Dynamic Table of Contents:
    The script automatically generates a table of contents based on the headers within your content. This helps users understand the structure of your content at a glance and navigate directly to the section they're interested in.
  2. Stylable Based on Heading Level:
    Each table of contents item is automatically given a CSS class that corresponds to its heading level (e.g., toc_h2, toc_h3), allowing for customization of style for each heading level.
  3. Active Section Highlighting:
    As the user scrolls through the page, the script identifies the current section being viewed and highlights it in the table of contents. This provides a visual cue to help users keep track of their position in the document.
  4. Interoperability with CMS:
    This script is designed to work with a content management system (CMS), allowing you to specify which heading levels to include in the table of contents.

The value provided by this script lies in function 4 because it improves the usability for long-form content:

  • In the past all h tags were considered by the script to generate the ToC.
  • Now, You can choose to what depth you want your ToC to be generated from right in your Webflow CMS (or any other headless CMS).

In general, a ToC improves usability for any content designed for reading:

  1. Enhanced Reader Experience: By offering a table of contents and active section highlighting, readers can quickly navigate to the sections that interest them and maintain their location in long articles or posts. This can significantly improve the reader's experience, especially on long and complex pages.
  2. SEO Benefits: By structuring your content with headings and providing anchor links to specific sections, you can potentially improve your content's search engine optimization (SEO). Search engines like Google use headings to understand the content's structure and topics, and anchor links make your page more navigable for users coming from search results.
  3. Accessibility: This approach is also beneficial from an accessibility perspective. It assists screen readers and other assistive technologies in understanding the organization of the page content, thus improving the accessibility of your webpage.

This script now provides a relatively simple and effective way to enhance the navigability of your webpage, improve reader experience, and potentially boost SEO, all of which are critical for a great blog or any other content-rich website.

Documentation for the Table of Contents (ToC) Generator

This script automatically generates a dynamic and stylable table of contents (ToC) from selected heading levels in a webpage. It creates unique anchor links for each heading and monitors the user's scroll position to highlight the active section in the ToC. The generator can be easily customized by specifying which heading levels (e.g., h2, h3, etc.) should be included in the ToC.

How It Works

The script follows these steps:

  1. It retrieves the ToC container and the heading selectors from the webpage.
  2. It assigns a unique ID to each heading based on its content, and creates a corresponding anchor link in the ToC.
  3. It uses the Intersection Observer API to monitor which heading is currently in the viewport as the user scrolls through the page.
  4. When a heading enters the viewport, the script highlights its corresponding link in the ToC by adding an 'active' class to it.


  1. Copy and paste the script into your webpage. The script should be placed within <script> tags, preferably just before the closing </body> tag for better performance.
  2. Ensure that your page has a container for the ToC with the ID toc and a content container with the ID content.
  3. By default, the script includes headings level h2 through h6 in the ToC. If you want to specify different heading levels, you can either
  • hard code it: replace the string in the headingsSelector variable with the levels you want to include, separated by commas (e.g., "h2,h3") and no spaces!
  • Or: Create a text field in your Webflow CMS where you can choose the levels you want to include, separated by commas (e.g., "h2,h3" - and no spaces!) directly in your CMS when you write a blogpost. Then, you have to replace the string in the headingsSelector variable with a field in Webflow.
  1. Now, the script automatically assigns each heading in the ToC a class of tocitem and toc_hX, where X is the level of the heading (e.g., h2). You can use these classes to style the ToC items in your CSS.
  2. The script also assigns an 'active' class to the ToC item corresponding to the heading that is currently in the viewport. You can use this class to highlight the active item in your CSS.

ToC Script

<!-- generate a TOC styleabel by headings level -->
let toc = document.querySelector("#toc");

let headingsSelector = "[wire up your Webflow dynamic field here]"; // Selector for Headings selected in CMS

// If no value provided, default to all headings-except h1 if (!headingsSelector || headingsSelector.trim() === "") { headingsSelector = "h2,h3,h4,h5,h6"; }

let headings = Array.from(document.querySelector("#content").querySelectorAll(headingsSelector));

let tocItems = headings.map((heading, index) => { let headingText = heading.textContent.trim().toLowerCase(); headingText = headingText.replace(/[^a-z0-9\s]+/gi, '').replace(/\s+/g, '-'); let id = ${headingText}-${index}; // ensure uniqueness

heading.setAttribute("id", id); heading.classList.add("anchor");

const item = document.createElement("a"); item.textContent = heading.textContent; item.href = #${id}; item.classList.add("tocitem", toc_${heading.tagName.toLowerCase()});


return item; // return the created tocItem });

// Use Intersection Observer API to determine when a section becomes visible const observer = new IntersectionObserver(entries => { entries.forEach(entry => { const id = entry.target.getAttribute("id"); if (entry.isIntersecting) { document.querySelectorAll(".active").forEach((z) => { z.classList.remove("active") }); document.querySelector(a[href=&quot;#${id}&quot;]).classList.add("active"); } }); }, { rootMargin: '0px 0px -75% 0px' });

// Observe each heading headings.forEach(heading => { observer.observe(heading); }); </script>


You can easily customize this script according to your needs. For example:

  • If you want to include all heading levels in the ToC, you can set headingsSelector to "h1,h2,h3,h4,h5,h6".
  • If you want to change the container of the ToC or the content, simply replace "#toc" or "#content" in the script with the selector of your desired container.
  • You can modify the Intersection Observer's root margin in order to change when a heading is considered to be in the viewport.


This script uses modern JavaScript features and should work in all modern browsers. It does not rely on any libraries or frameworks, so it can be used in any JavaScript environment. Might not work in Internet Explorer, as the Intersection Observer API is not supported there.

Read next in DOCU

Optimize Netlify Build Minutes and DecapCMS by Skipping Unnecessary Builds

Optimize Netlify Build Minutes and DecapCMS by Skipping Unnecessary Builds

Read next in DOCU

Displaying Both the Publication and Update Dates on Webpages

Showing both the update and the publish date on your blog / web page seems to be difficult for Search Engines and therefore it seems like only displaying “last updated” is the safer way. If your blog shows more than one date, you are probably confusing Google.

Read next in DOCU

Localization: The "hreflang" Tag Accross Different Domains

John Mueller on how to use the hreflang tags across domains for the localization schemas: It doesn't matter if it's all on one domain or across multiple domains. It should just be one clear place per country and language.

Read next in DOCU

DecapCMS Markdown Guide: Handling URLs with Parentheses for Text Fragment Highlighting

Are broken links in your DecapCMS Markdown articles giving you a headache? never let parentheses break your links again: handle text fragment highlighting in Markdown. No more parentheses-induced troubles in your Github articles built with Netlify!

Read next in DOCU

Leveraging a Small JavaScript for a Quick Multilingual Strategy in Webflow

A button that appears when there is an alternate language defined for your content, making your cotent more relevant to your users experiences. Implementing a Dynamic Language Switcher Button with JavaScript

Read next in DOCU

Interactive URL Copy Feature in Webflow Using Clean JavaScript and Clipboard API

An interactive URL copy feature in Webflow. Using clean JavaScript and the powerful Clipboard API, making it easier for visitors to share your pages. Because who doesn’t appreciate a great user experience?

Read next in DOCU

An Extensive Dynamic Table of Contents Generator for Webflow CMS

Boost your Webflow Blog's readability and SEO with a dynamic Table of Contents (ToC) generator. It automatically creates a stylable, navigable ToC from your headings, and enhances user experience by highlighting the active section during scrolling.

Read next in DOCU

Styling Our Auto-Generated ToC in Webflow

Read next in DOCU

Creating or Changing Slugs in DecapCMS (formerly Netlify CMS)

Changing the URL Slug of your post in DecapCMS in config.yaml using the slug key and name key

Read next in DOCU

Smooth Scrolling to the Next Section with JavaScript and [foo](#next) markdown syntax

When I write [[`foo`](#next)`](#next)` markdown syntax in my content I want the reader to jump to the next section, the next anchor, on my webpage.

Read next in DOCU

Vimeo vs YouTube Embed for your Website

Consider this when you decide between YouTube or Vimeo for Website embeds

Read next in DOCU

Editorial Workflow in Decap CMs (formerly Netlify CMS)

Read next in DOCU

README for ChatGPT and How to Write the Best Prompts

When answering prompts, does it help ChatGPT to be more specific and precise if you give it a set of definitions upfront?

Read next in DOCU

Use Hash-symbol vs Triple-quotes Syntax for Commenting Python Code

Consider this when you choose the syntax for commenting code in Python

Read next in DOCU

Dynamically Generated ToC with Webflow CMS

Generating ToC’s based on h2 and h3 headings of a rich text CMS element with active states in a sticky Table of Contents

Read next in DOCU

Dynamic Social Media Share Buttons for Webflow CMS Blogposts

Add a Twitter button and a share on LinkedIn to your blogposts with sharing content generated from Webflow CMS

Read next in DOCU

Calculate Read Time from Webflow CMS

Calculated a read time from Webflow CMS and add to your blog template.

Read next in DOCU

Add Copy-able Code Blocks to Webflow CMS

Uses highlight.js and custom code to add code blocks where you can copy the code to rich text element of Webflow CMS

Hej. I am on Twitter, too.

Connect with me on Twitter and LinkedIn.