In this tutorial, I'm going to show you how to improve the active styles for the Elementor table of content element.
We are going to improve when the active styles are on*, and we are going to add a triangle indicator too, as well as a line.
*By default, Elementor has a few options for the active styling of the table of content list items. You can change the typography to make the active list item bold, for instance.
One major problem though is that the timing isn't quite right. As soon as the title gets in the viewport, it's applying these styles. Then when going back up, as soon as another heading gets in the viewport, it's switching to that one. This results in inconsistent and inaccurate active styling.
Here is an example of Elementor's native option in action (NOT what we are doing):
So I worked very carefully to get my version to be consistent: it won't be jumping from one active list item to another seemingly randomly. When a heading gets to 30% from the bottom in the viewport, the related table of content list item gets active. When it leaves that area, the one before gets active.
Here is my improved version in action. That's what this tutorial will show you how to do:
Visit the demo page directly to see it in action better, sometimes the Intersection Observer API (which we are using here) is a bit buggy when going through an iFrame.
You will be able to customize the colors and styles of the line, triangle and active item typography.
Let's get started!
First, get your design ready
This is a premium tutorial. Purchase access to unlock the full tutorial and access the code snippet.
8 Responses
Hello, great work thanks !
Do you think that will work on standard anchors here and there in a page? to summarize, i sometimes create fixed submenus in a page with anchors. I'm trying to change the style of the active anchor and i'm wondering whether the solution proposed here with the table of contents would also work with standard anchors.
Thanks !
Greetings Cyloe!
You don't need this to make it work with a normal menu with anchor links... you don't need any custom code. Here is how you do it:
First, you need to use the Elementor "WordPress Menu" element. That element has settings (under Style tab) for the active state.
Then, you need to be certain that the anchor IDs are given to the containers (avoid using the Menu Anchor element, instead go under Advanced > CSS ID and set the ID there). Here is the really important part: You will want the containers with the IDs to be directly one after another.
Example: you have #id1 , #id2 and #id3 .
Even if in the section of the page that's #id1, you have lots of content, you will want to move all of it within a parent container that has the CSS ID "id1".
Then, the container directly after this (CSS ID "id2") should have everything within it that belongs to this part of the page.
Same for #id3.
Point is, there can't be any space inbetween the containers with the IDs, otherwise your menu items will lose their "active" styles while the scroll position is no longer over a container with a related anchor ID.
I hope this helps!
Cheers!
Hello Maxime,
Many thanks for your answer. sorry for not being specific enough. I don't use wordpress menu or any king of menu. It's just random words displayed as a menu that are suppose to be anchor links. I finally used a plugin. But if there is a way without plugin I'll be glad to read it 😉
Thanks again and have a good day !
Hello.
Thanks Form thus code.
Question: I use the TOC as a stick element and closed.
Now I would like (in the tablet and mobile view) that the TOC closes automatically after I have opened it and clicked on a point.
Do you know how to implement this?
Thanks
Greetings Jurgen!
I have just published this tutorial for you: https://element.how/elementor-close-table-of-content-on-link-click/
Cheers!
Hey Maxime,
I am using this active style just like the content above, only I set the rootMargin to: rootMargin: "30px 0px -35% 0px", which works best for my design. The only problem I have is that when I refresh the page, the arrow sometimes start at point 3 instead of 1. It seems to start at random points when all I want is the arrow to start at the first h2 element. How can I fix this?
Greetings!
Please try this. Add:
setTimeout(() => {
tocItems.forEach(e => e.classList.remove('isActive'));
tocItems[0].classList.add('isActive');
}, 40);
Just before the curly bracket here, before the end of the script tag:
}
</script>
Let me know if that woks!
Cheers!
You're the best!