Accessible Table of Contents in Webflow, No Code

Intermediate 23:11 webflowtable-of-contentsaccessibilityno-codeattributes

Build a responsive, accessible table of contents in Webflow with no code — auto-highlighting links, collapsible heading groups, and a mobile popup panel.

Key takeaways

  • The whole thing is attribute-driven — the script only ever reads the fc-toc attributes, so your class names and naming convention are completely irrelevant.
  • The list is generated at runtime by scanning the headings inside your rich-text element, so it always matches whatever the CMS renders — you never hand-build or maintain the list.
  • Real accessibility comes from semantics, not styling: a nav tag, an aria-label, and an ordered list tell screen readers this is page navigation with a clear hierarchy.
  • Collapsible groups are opt-in with a single attribute, and the script keeps you oriented — a group that holds the currently active link cannot be collapsed, so you never lose your place.
  • Sticky positioning plus a capped max-height with overflow auto keep the TOC usable at any length, and on small screens it turns into a slide-up popup panel instead of eating the layout.

Video chapters

  1. 00:00 Intro
  2. 01:14 Project Structure & Solution Configuration
  3. 11:20 Collapsible Link Groups
  4. 15:59 Code Overview & Documentation
  5. 19:28 Responsiveness
  6. 22:00 Outro

Give any long blog post a clean, responsive, and fully accessible table of contents in Webflow — with no code you have to write yourself. It generates itself from your headings, highlights the section you’re currently reading, follows you down the page, and folds into a tidy popup on mobile.

The best part is how little it asks of you. There’s no library or plugin, nothing to hand-build, and your class names don’t matter at all — the script only cares about a small set of fc-toc attributes. Label a few elements, drop in the rich-text field, and the list appears.

And it’s accessible by design, not as an afterthought: it announces itself properly to screen readers, communicates the heading hierarchy, and behaves predictably whether someone is scrolling, clicking, or tabbing through with the keyboard.

How it works

Everything hangs off one wrapper. The element carrying fc-toc="wrapper" is a two-column grid: the TOC in the first column, the actual post content in the second, aligned to the top so the sticky TOC only takes the space it needs. Inside it, the rich-text element (bound to your CMS post-content field) gets fc-toc="content" — that’s the source the script scans for headings. Point the script at that element and it walks the H2–H6 inside, builds a link for each, and injects them into the list.

That list is the heart of it. It’s an element with its HTML tag set to nav and an aria-label="table of contents", so assistive tech announces it as a named navigation region — a small change that makes a big accessibility difference. Its position is sticky with a top offset matched to your navbar height, so it follows the reader down the page. Inside sits an ordered list (ordered on purpose: it communicates sequence and hierarchy to screen readers better than an unordered one) carrying fc-toc="component" — the container the links are injected into. A capped max-height (around 50vh) with overflow: auto means the TOC scrolls internally instead of growing forever and breaking the layout.

You seed the list with one list item per heading level you want to include, and each link inside gets fc-toc="h2" (through h6). That’s how the script knows which level a link represents — include only h2 to h4 and it simply builds three levels. As you scroll, the script adds the class you’ve marked with fc-toc="active-style" to whichever link is in view, and auto-scrolls the panel to keep that active link centered. Because the active state is driven by that attribute, the name of the class is irrelevant — style it however you like.

Collapsible groups are optional and turn on with a single attribute: add fc-toc-collapse="true" to the ordered list and only the H2 links show at first, each with a toggle icon marked fc-toc="open-group" (and fc-toc-rotate for how far it spins when open). Groups expand automatically as you scroll into them and collapse as you leave — with one thoughtful guardrail: a group holding the currently active link can’t be manually closed, so you never lose track of where you are. One catch worth remembering: the collapsible wrapper relies on a helper element with the exact class toc-subitems, which the script looks for by name — it must be spelled exactly and live on the same page.

On small screens the TOC would eat too much room, so it converts into a popup panel: a sticky button (built with the actual button tag) triggers a click interaction that slides the panel up from the bottom over a blurred, semi-transparent background. Tap the background or a link and it slides back down and hides. This lives on a Webflow interaction from the tablet breakpoint down — no extra attributes needed.

How to use it

  1. Clone the project. Grab the Webflow cloneable — it ships with the full structure, the commented script, and a complete attribute reference on the project’s homepage. It’s built on the free Notable blog template.

  2. Mark the wrapper and content. Put fc-toc="wrapper" on the two-column container that holds the TOC and the post body, and fc-toc="content" on the rich-text element whose headings you want listed (typically your CMS post-content field).

  3. Set up the TOC element. On the TOC container, set the HTML tag to nav and add aria-label="table of contents". Give it position: sticky with a top offset that matches your navbar height.

  4. Build the list scaffold. Inside, add an ordered list with fc-toc="component". Add one list item per heading level you want, and on each item’s link set fc-toc="h2"fc-toc="h6" to match. Cap the list with max-height and overflow: auto.

  5. Mark the active style. On the class you want applied to the in-view link (a colored left border, a different text color — whatever you like), add fc-toc="active-style". The script toggles this class as you scroll.

  6. (Optional) Turn on collapsible groups. Add fc-toc-collapse="true" to the ordered list. Give the H2 list item a toggle icon with fc-toc="open-group" (and fc-toc-rotate if you want a rotation other than -45°), and add the required toc-subitems helper element (spelled exactly) on the page with overflow: hidden, max-height: 0, and a max-height transition for the smooth open/close.

  7. Check mobile. The cloneable already includes the sticky open button and the slide-up popup interaction from the tablet breakpoint down — publish and test that the panel opens, links jump to the right heading, and the active link stays centered.

Configuration reference

Attribute Values Default What it does
fc-toc wrapper · content · component · h2 … h6 · active-style · open-group The role marker the whole solution reads. Put "wrapper" on the grid that holds both the TOC and the content, "content" on the rich-text element to scan for headings, "component" on the ordered list where links get injected, a heading value ("h2" through "h6") on each list item's link so the script knows which level it represents, "active-style" on the class you want applied to the in-view link, and "open-group" on the toggle icon that expands a collapsible group.
fc-toc-collapse true not set (expanded) Add it to the ordered list (the "component") with the value true to start every subheading group collapsed, so only the top-level H2 links show until the reader expands them or scrolls into a section. The script compares against the exact string "true", so any other value — or leaving the attribute off — keeps all links visible and expanded.
fc-toc-rotate degrees (positive or negative) -45 How far the group-toggle icon rotates when its group is open — pure visual feedback. Put it on the same icon that carries fc-toc="open-group"; leave it off and it defaults to -45°.

Resources

Frequently asked questions

How do I add a table of contents to a Webflow blog post without code?
Clone the project, mark your rich-text element with fc-toc="content" and an ordered list with fc-toc="component", then add one list item per heading level you want to include. The script scans the content, finds the headings, and injects the links for you — you never write the list by hand.
Will the table of contents work with Webflow CMS content?
Yes. It reads the headings straight out of the rich-text field it is pointed at, so every collection item generates its own list from whatever that post actually contains. Nothing is hard-coded per page.
How do I make a Webflow table of contents accessible to screen readers?
Set the TOC element's HTML tag to nav and give it aria-label="table of contents" so assistive tech announces it as a named navigation region. Using an ordered list (rather than unordered) also communicates the sequence and hierarchy of the sections more clearly.
How do I show only the main headings and let readers expand the rest?
Add fc-toc-collapse="true" to the ordered list. Only the top-level (H2) links show at first, each with a toggle icon marked fc-toc="open-group" that expands the subheadings beneath it. Groups also open automatically as you scroll into that section.
How does the table of contents behave on mobile?
Instead of taking up permanent space, it becomes a popup panel triggered by a sticky button. Tapping the button slides the panel up over a blurred background; tapping the background or a link closes it again.