Dynamic Webflow Table of Contents

This video tutorial provides a comprehensive guide to building a fully dynamic, no-code Table of Contents (TOC) for Webflow projects, specifically designed for long-form blog posts or editorial content. The presented solution eliminates the need for external plugins or writing complex JavaScript from scratch by utilizing a system of custom attributes that automatically scans Rich Text elements to generate navigational links. The instruction ensures that the resulting component works seamlessly with both static and CMS-driven content, prioritizing a clean architecture that requires only a single code embed to function.

The technical implementation focuses on structure and hierarchy, teaching viewers how to configure a "post-content wrapper" that houses both the main text and the sticky navigation sidebar. Key configuration steps include assigning specific attributes such as fc-toc="content" to the source text and fc-toc="component" to the list container, which allows the script to dynamically inject headings ranging from H2 to H6. Furthermore, the video emphasizes high accessibility standards by utilizing semantic HTML tags like <nav> and ordered lists (<ol>) to ensure compatibility with screen readers and assistive technologies.

Beyond basic functionality, the tutorial covers advanced user experience features, including active state highlighting and collapsible heading groups for a cleaner interface. The guide also details a robust mobile strategy where the desktop sidebar transforms into a button-triggered, animated pop-up panel on smaller viewports to preserve screen real estate. By following this workflow, developers achieve a polished, responsive navigation system that enhances content discoverability and maintains context for the reader through automatic scrolling and centering behaviors.

Key Takeaways

  • Attribute-Based Configuration: The system relies on specific custom attributes, such as fc-toc="content" for the source text and fc-toc="component" for the output list, to dynamically generate links without manual coding.
  • Accessibility First: The build prioritizes semantic structure by using the <nav> tag and ARIA labels (aria-label="Table of Contents"), ensuring the navigation is interpretable by screen readers.
  • Dynamic Active States: As users scroll, the script automatically applies an active class (defined by fc-toc="active-style") to the current link and auto-scrolls the TOC panel to keep the active item centered in view.
  • Collapsible Hierarchy: By applying fc-toc-collapse="true", the TOC can nest sub-headings (e.g., H3s under H2s) into expandable groups, reducing visual clutter while allowing users to drill down into specific sections.
  • Adaptive Mobile Design: To resolve space constraints on smaller devices, the sticky desktop sidebar is replaced by a custom trigger button that opens a modal-style pop-up panel anchored to the bottom of the viewport.

Timestamps

  • 2:08 – Assigning the custom attribute fc-toc="wrapper" to the main container holding both the TOC and the content.
  • 2:37 – Setting the wrapper grid gap to 5rem and vertical alignment to "top" to ensure proper sticky behavior.
  • 3:27 – Applying the attribute fc-toc="content" to the Rich Text element so the script knows where to source headings.
  • 4:12 – Setting the TOC element to position: sticky with a top offset of 150px.
  • 4:37 – Changing the TOC container’s HTML tag to <nav> for semantic accessibility.
  • 5:00 – Adding the attribute aria-label="Table of Contents" to the navigation element for screen readers.
  • 5:43 – restricting the list height by setting max-height to 50VH and overflow to "auto" to prevent layout breakage.
  • 6:24 – Assigning the attribute fc-toc="component" to the ordered list, designating it as the target for dynamic link injection.
  • 8:36 – Adding attributes to the template links (e.g., fc-toc="h2") to map them to specific heading levels.
  • 9:21 – Assigning fc-toc="open-group" to the icon element to function as a collapse/expand toggle.
  • 9:26 – Setting the fc-toc="rotate" attribute (e.g., -45) to define the icon's animation during interaction.
  • 10:13 – Defining the active class for the script to use by applying the attribute fc-toc="active-style".
  • 11:40 – Enabling the collapsible hierarchy feature by adding the attribute fc-toc-collapse="true" to the main list.
  • 13:09 – Creating a specific container div with the mandatory class name toc-sub-items to wrap collapsible groups.
  • 13:59 – Setting overflow: hidden and max-height: 0 on the sub-items container to create the dropdown effect.
  • 16:08 – Placing the custom code embed containing the JavaScript inside the post-content wrapper.
  • 20:20 – Applying a click interaction to the sticky button (tablet breakpoint) to trigger the mobile pop-up panel.

How to Build a Dynamic, No-Code Table of Contents in Webflow

Phase 1: Structure and Configuration

1. Set Up the Project Wrapper

Timestamp Reference: 02:08 – 02:40

  • How: Select the main container element that holds both your future TOC and your blog post content (e.g., post-content-wrapper). Apply the custom attribute fc-toc="wrapper". Ensure this element is set to a two-column Grid (or Flex) with vertical-align: top.
  • Why: This attribute defines the scope for the script, identifying the container that holds both the source content and the navigation list. Vertical alignment set to "top" prevents the sticky element from stretching the full height of the container, ensuring sticky scrolling works correctly.

2. Connect the Source Content

Timestamp Reference: 03:27 – 03:40

  • How: Select the Rich Text element connected to your CMS post content. Add the attribute fc-toc="content".
  • Why: This tells the script exactly which text element to scan. The code will look inside this element to find headings (H2–H6) and generate the links.

3. Position the TOC Container

Timestamp Reference: 04:12 – 04:28

  • How: Select the element intended to be the TOC (e.g., blog-post-toc). Set its position to sticky and define a top offset (e.g., 150px).
  • Why: This ensures the TOC follows the user down the page as they read. The offset prevents the TOC from being hidden behind a fixed navbar or sitting too close to the top edge.

4. Configure Accessibility Settings

Timestamp Reference: 04:37 – 05:00

  • How: In the element settings panel for the TOC container, change the HTML tag to <nav>. Add the attribute aria-label="Table of Contents".
  • Why: Using <nav> identifies the section as a navigation aid to assistive technologies. The ARIA label gives the region a specific name that screen readers can announce to users.

5. Configure the List Component

Timestamp Reference: 05:26 – 06:24

  • How: Inside the TOC container, use an Ordered List (<ol>) element. Add the attribute fc-toc="component". In the styles panel, set max-height (e.g., 50vh) and overflow: auto.
  • Why: The Ordered List communicates hierarchy and sequence to screen readers. The component attribute designates this list as the target where the script will dynamically inject the generated links. The max-height settings ensure the list becomes scrollable rather than breaking the layout if the post is very long.

Phase 2: Item Template & Styling

6. Create Heading Templates

Timestamp Reference: 06:45 – 08:36

  • How: Inside the list, create a list item for each heading level you wish to support (e.g., H2, H3). Inside each item, place a text link. Add the attribute fc-toc="h2" to the link corresponding to Heading 2, fc-toc="h3" for Heading 3, and so on.
  • Why: These items serve as templates. The script uses the specific attribute (e.g., fc-toc="h2") to map a heading found in the text to the specific visual style you created for that level.

7. Define the Active State

Timestamp Reference: 09:42 – 10:13

  • How: Create a specific class (e.g., u-doc-current-link) with your desired active styling (e.g., colored text or border). Select your link template and add the attribute fc-toc="active-style", pointing to that class.
  • Why: This attribute tells the script which class to apply when a specific heading scrolls into view. The script automatically toggles this class on and off as the user reads.

Phase 3: Advanced Functionality (Collapsible Groups)

8. Enable Collapse Logic

Timestamp Reference: 11:22 – 11:40

  • How: Select the main Ordered List element again. Add the attribute fc-toc-collapse="true".
  • Why: This activates the functionality where sub-headings (like H3s) are hidden until their parent group is active, creating a cleaner, compact interface.

9. Add Toggle Icons

Timestamp Reference: 12:06 – 12:54

  • How: Inside the H2 list item, add an icon element. Add the attribute fc-toc="open-group" to the icon. Optionally, add fc-toc="rotate" with a value (e.g., "-45").
  • Why: The open-group attribute designates the icon as the trigger button to manually expand or collapse a section. The rotate attribute defines the animation angle for the icon when the group is open.

10. Create the Sub-Items Container

Timestamp Reference: 13:09 – 14:10

  • How: Create a div block anywhere on the page (e.g., near the rich text) and give it the specific class name toc-sub-items. Set this class to overflow: hidden and max-height: 0.
  • Why: This class name is mandatory as it is referenced internally by the script. It acts as the wrapper for nested groups; setting the height to zero ensures they are hidden by default and animate open smoothly.

Phase 4: Implementation and Mobile

11. Implement the Script

Timestamp Reference: 15:59 – 16:15

  • How: Add an Embed element containing the provided JavaScript code inside your post-content-wrapper (or page footer).
  • Why: This script powers the entire system: scanning content, injecting links, handling scroll spying, and managing animations.

12. Configure Mobile Responsiveness

Timestamp Reference: 19:20 – 20:41

  • How: Hide the sticky sidebar on Tablet/Mobile. Create a sticky "Open TOC" button visible only on smaller breakpoints. Apply a click interaction to the button that triggers a pop-up modal containing the TOC list.
  • Why: A permanently visible sidebar takes up too much room on mobile screens. Using a button-triggered modal preserves screen real estate while keeping navigation accessible.

FAQs

How to build a dynamic table of contents in Webflow without plugins?

To create a no-code solution, apply the custom attribute fc-toc="content" to your Rich Text element and fc-toc="component" to an empty ordered list block. Use a custom JavaScript embed to automatically scan the text for H2–H6 headings and dynamically inject corresponding anchor links into your list container.

How to make a Webflow table of contents accessible for screen readers?

Set the navigation container's HTML tag to <nav> and add the attribute aria-label="Table of Contents" to clearly define the region for assistive technology. Additionally, use an ordered list (<ol>) structure to communicate the content hierarchy and sequence effectively to users relying on screen readers.

How to create collapsible nested groups in a Webflow table of contents?

Apply the attribute fc-toc-collapse="true" to your main list and use a toggle icon with the attribute fc-toc="open-group" to control visibility. Wrap the collapsible sub-items in a div with the specific class toc-sub-items, setting its overflow to hidden and max-height to zero to create a dropdown effect.

How to highlight active links in a Webflow table of contents while scrolling?

Create a specific CSS class that defines your active state (e.g., a colored border) and assign it to the link element using the attribute fc-toc="active-style". A script will then track the viewport and automatically apply this class to the navigation link corresponding to the heading currently visible on the screen.

This is some text inside of a div block.