Learn how to create a sticky table of contents that highlights the section you're currently reading in Webflow.
In this tutorial, Sandro, cofounder of Gemeos Agency, a Webflow agency, shows you how to create a sticky table of contents that highlights the section you’re currently reading in Webflow.
Example
Scroll through the article area to see the active section in the table of contents
Introduction
Webflow is a no-code tool that generates clean, high-performance code for modern teams.
Setup
Create an account on webflow.com and start a new project from the available templates.
Configuration
Define your CSS variables, color system, and responsive breakpoints.
Publishing
Connect your domain and publish in one click from the Webflow Designer.
| Element | ID/Class | Description |
|---|
| Table of contents container | id='sticky-toc' | Sticky-positioned in a sidebar |
| Article area | class='article-content' | Source of the H2s being analyzed |
| Active section | Purple border | Updated automatically on scroll |
1. Build the structure in Webflow
Create a two-column layout: left column for the article (class article-content), right column for the table of contents. In the right column, create a Div with the ID sticky-toc and apply position: sticky; top: 24px;. Set it to display: none by default.
2. Add the script in Footer code
(function() {
var toc = document.getElementById('sticky-toc');
var content = document.querySelector('.article-content');
if (!toc || !content) return;
var headings = content.querySelectorAll('h2');
if (headings.length < 2) return;
var ul = document.createElement('ul');
ul.style.cssText = 'list-style:none;padding:0;margin:0;';
headings.forEach(function(h, i) {
if (!h.id) h.id = 'section-' + i;
var li = document.createElement('li');
var a = document.createElement('a');
a.href = '#' + h.id;
a.textContent = h.textContent;
a.dataset.target = h.id;
a.style.cssText = 'display:block;padding:6px 12px;font-size:13px;color:#6b7280;' +
'text-decoration:none;border-left:2px solid transparent;transition:all 0.15s;' +
'border-radius:0 6px 6px 0;';
a.addEventListener('click', function(e) {
e.preventDefault();
document.getElementById(h.id).scrollIntoView({ behavior: 'smooth' });
});
li.appendChild(a);
ul.appendChild(li);
});
toc.appendChild(ul);
toc.style.display = 'block';
// Highlight active section
window.addEventListener('scroll', function() {
var active = null;
headings.forEach(function(h) {
if (h.getBoundingClientRect().top <= 120) active = h.id;
});
toc.querySelectorAll('a').forEach(function(a) {
var isActive = a.dataset.target === active;
a.style.color = isActive ? '#111' : '#6b7280';
a.style.fontWeight = isActive ? '500' : '400';
a.style.borderLeftColor = isActive ? '#a78bfa' : 'transparent';
a.style.background = isActive ? 'rgba(167,139,250,0.08)' : 'transparent';
});
}, { passive: true });
})();
good to know
On mobile, a sticky sidebar doesn’t make sense. Hide sticky-toc on mobile with a media query: @media (max-width: 768px) { #sticky-toc { display: none !important; } }. Instead, offer an inline table of contents at the top of the article, generated by the same script.
Conclusion
A sticky table of contents with an active section significantly improves navigation on long articles. Use cases:
- Documentation articles with 5+ sections
- Technical guides with numbered steps
- Comparison pages with multiple criteria