I’m trying to create a sticky table of content with active state.
I used this tutorial from @aaro .
I’m not a developer and have been scratching my head all morning on two issues:
The table of contents detects the title at the bottom of the page as active state. I would like to highlight the title at the top of the page instead.
In-page navigation scrolls to a heading behind the navigation bar.
I found some threads explaining how to solve the second issue but switching position of header to “fixed” breaks everything and I cannot manage to fix it afterwards.
Awesome, I had no idea about the “tag” feature.
It works, I need to learn why but it solved the second issue!
Thank you!
For the first one, I understand I’m linking to the heading.
So if the heading is visible, the intersection ratio is 1 and active state is selected.
So I need to actually check when precedent title has left the screen instead of trying to check when next title is in the screen. but how …
EDIT 2 : Maybe I should set everything to active, and when it’s not intersecting, remove the active class.
I managed to solve the first issue by setting up the root margin in the code.
Here is the code I used:
<script>
const options = {
rootMargin: '0px 0px -80% 0px'
};
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="#${id}"]`).classList.add("active");
}
});
},options);
</script>
<script>
document.getElementById("content").querySelectorAll("h2,h3,h4").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
("h2,h3,h4").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
});
</script>