Dynamic TOC for Multilingual Jekyll Posts
Why a Multilingual Table of Contents Matters
Longform content needs a navigable structure to help users skim and understand context. In multilingual websites, it's not enough to generate a generic ToC—you need to respect the language of the user, label sections accordingly, and ensure the experience remains consistent across locales.
In this tutorial, we’ll build a reusable, dynamic table of contents system for Jekyll posts that adapts based on language, using Liquid for static structure and JavaScript for client-side interaction.
Planning the Multilingual Navigation
We want to achieve the following:
- Detect headings within the article content
- Generate anchor links with readable text in the correct language
- Enable smooth scrolling
- Make it reusable across all posts
We'll separate content logic from layout logic using includes and data-driven design.
Step 1: Add Headings with ID Attributes
Make sure your headings have an `id` attribute for linking. If using Markdown, Jekyll automatically assigns slug-based IDs to headings. For manual HTML, you should write:
Introduction
Step 2: Create a ToC Include File
Create an include file named _includes/toc.html with the following content:
{% raw %}
{% endraw %}
This script collects all h2 and h3 elements and dynamically builds the list when the page is loaded.
Step 3: Add Language Support via Data Files
Create a file in _data/lang.yml with the following structure:
en:
toc_title: "Table of Contents"
es:
toc_title: "Índice de Contenidos"
Make sure your posts set the `lang` front matter:
lang: en
Step 4: Insert ToC into Layout
Edit your layout file (e.g. _layouts/post.html) and add the include where you want the ToC to appear:
{% raw %}{% include toc.html %}{% endraw %}
Step 5: Style the ToC
Add CSS to enhance readability:
#toc {
background: #f9f9f9;
padding: 1em;
border: 1px solid #ddd;
margin-bottom: 2em;
}
#toc h3 {
margin-top: 0;
}
#toc-list {
list-style: none;
padding: 0;
}
#toc-list li {
margin-bottom: 0.5em;
}
Optional: Smooth Scrolling
Add smooth scrolling behavior via CSS:
html {
scroll-behavior: smooth;
}
Optional: Collapse ToC Sections
To support posts with many headings, consider enhancing the list with collapsible sections:
- Wrap subheadings in nested `
- ` tags
- Use JavaScript to toggle visibility
Making the ToC Reusable Across Languages
By using `page.lang` and the `lang.yml` data file, the ToC heading and structure become automatically translatable. You can extend this by adding localized tooltips or button labels as well.
Benefits of This Approach
- No third-party libraries required
- Works entirely on the client side
- Fully adaptable to any language
- Reusable across all posts
Use Cases and Examples
- Documentation pages with technical walkthroughs
- Longform blog articles with multiple sections
- Tutorials that span many h2/h3 subsections
Conclusion
With just Liquid and a bit of JavaScript, you can provide multilingual-aware navigation within any Jekyll page. This boosts readability, improves UX for global audiences, and requires zero dependencies. In the next guide, we’ll explore how to dynamically highlight the current section as the user scrolls—a feature often referred to as “scroll spy.”
