[TUTORIAL] Dynamic Table of Contents on Webflow CMS (no plugins, automatic)

Looking for an easy way to automatically generate Table of Contents for your blog posts or other CMS items?

I recently built a system that dynamically generates ToCs based on the headings (H2, H3, etc.) of any Rich Text field. Super easy to set up, less than 10 lines of code, and no plugins.

Find the full blog post with images, gifs, and code snippets here :point_right: https://www.flowrite.com/blog/dynamic-table-of-contents-on-webflow-cms

8 Likes

@aaro This is so cool!

1 Like

Super cool, thanks a ton for this!

1 Like

it’s great work. Small question – does it have active state?

Thanks! What do you mean exactly?

something like this – http://joxi.ru/GrqjeX6tG98vOm

Hi Aaro,

did you have a chance to look at my question?

Yes! I made that work with an additional code snippet. I’ve included the instructions in the blog post – hope it helps!

activescroll

2 Likes

it’s incredible. You are wonderful. thanks a lot :pray::pray::pray:

1 Like

Hey there Aaro, this is awesome - and a nice replacement for http://projects.jga.me/toc/

I have a question: This is for SEO reasons, and it is the reason I’m considering leaving the TOC jquery plugin.

Is there a way that you can generate the ToCs based on headings through the page, but have the links in the TOC be " p tags vs H2s"

The TOC plugin, unless I’m mistaken, auto creates the TOC links as H2s on the page. This caused me an SEO issue because H2s are now repeated on page.

Here is an example of the current blog post I’m using jquery for.

Hi Aaro,

did you have a chance to look at my question?

Hi @aaro are you able to paste all the code in structure? I can’t seem to make the active toc work.
because the tutorial is adding the code 1 by 1 without showing all the code in final.

I found an error when adding this part

observer.observe(heading);

my current code looks like this


if("{{wf {"path":"table-of-content-based-on","type":"PlainText"\} }}"!=""){

const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    const id = entry.target.getAttribute("id");
    if (entry.isIntersecting) {
      document.querySelectorAll(".active-link").forEach((z) => {
        z.classList.remove("active-link")
      });
      document.querySelector(`a[href="#${id}"]`).classList.add("active-link");
    }
  });
}, { rootMargin: '0px 0px -75% 0px' });

}

document.getElementById("content").querySelectorAll("{{wf {"path":"table-of-content-based-on","type":"PlainText"\} }}").forEach(function(heading, i) { // runs a function for all headings inside your rich text element
observer.observe(heading);
	heading.setAttribute("id", "toc-" + i); // gives each heading a unique id
  const item = document.createElement("a"); // creates an anchor element called "item" for each heading
  item.innerHTML = heading.innerHTML; // gives each item the text of the corresponding heading
  ("{{wf {"path":"table-of-content-based-on","type":"PlainText"\} }}").split(",").forEach(function(x) { // runs a function for each item in your headings list
    if (heading.tagName.toLowerCase()==x) {
      item.classList.add("tocitem", "toc-" + x); // gives each item the correct class
    }
  });
  item.setAttribute("href", "#toc-" + i); // gives each item the correct anchor link
  document.querySelector("#toc").appendChild(item); // places each item inside the Table of Contents div
});


Also curious if there’s any update on this, I’m erroring out on the same spot:

observer.observe(heading);

The addition seems to just shut down the TOC JS entirely.

Hi Jon. Everything seems to be working correctly on my end with the same code, but let me see if I can help here. Can you send me a link to your site?

1 Like

Thanks @aaro, I’m testing out on this example blog post, and here’s the read-only link.

It looks like you’re trying to call the observer function with observer.observe(heading) but you haven’t defined it in the first place. Please make sure to add the code starting with const observer = new IntersectionObserver(entries... from the blog above your current code.

You can also benchmark our blog where I’ve implemented this successfully: How to write a reminder email — 5 examples and templates

Hope this helps :blush:

I am new to Webflow and having a dynamic ToC would be great, but I am missing something from this resource - I just cannot understand what are the steps to make it work.

Adding the script is the easy part, but I don’t know what Elements I need to add and where the CSS classes go to generate the ToC for the articles.

What am I missing from the article How to Create Dynamic Table of Contents on Webflow CMS

1 Like

Hey everyone!

If you need to dynamically generate a table of contents but don’t want to bother with the step-by-step tutorials this cloneable project is for you! :grin:

I followed Aaro’s tutorial for ToC pulling just one header type. Nice and simple!

Kapture 2022-03-18 at 09.08.24

1 Like

Hello.

I was trying to set up the ToC as showed in the guide, and I really thought I’ve followed it on the spot, but it doesn’t seems to work for me.

I created the links, giving them classes of: tocitem and toc-h2 toc-h3 etc etc
Created the div with the ID “toc”
Also gave the rich text the ID “content”
I’ve added the new field on the collection called “TOC based on…” and added the h2,h3,h4 etc etc without spaces or anything
And ultimately, placed the custom code, changing the “HEADINGS” text with the “TOC based on…” everywhere (placed it at the end of the page as an embed, and also tried on the page menu before the body tag"

I really don’t now what I’m getting wrong, can someone be so kind to give me a direction?
This is the read only link:
https://preview.webflow.com/preview/samueles-project-42869b?utm_medium=preview_link&utm_source=designer&utm_content=samueles-project-42869b&preview=9f914086602b61f18774b1f90db28df1&pageId=625152e2362e3536ef4a94a3&itemId=625152e6544f7623224cb10c&workflow=preview

Thank you so much, Sam

1 Like

Search for “How to Create a Table of Contents (TOC) in Webflow in Under 20 Minutes” in YouTube

1 Like