Toccer is the table of contents (TOC) generator of the J1 Template. The module scans the headings of a page (h1 .. h6) and builds a clickable table of contents from them. While the visitor scrolls, the entry that matches the current section is highlighted automatically, and nested sections open and close like an accordion.
Toccer is based on Tocbot, a small, dependency-free JavaScript library written by Tim Scanlin. Tocbot was inspired by Tocify, but works natively without the need for jQuery. In the J1 Template, the Tocbot core is wrapped by the Toccer adapter, which reads your YAML settings, waits until the page is ready, and then starts Tocbot with the configured options.
| The Toccer API documentation pages are based on Tocbot version v4.36.8 for the current J1 template version 2026.x. The idea of providing this documentation is not to simply copy the original Tocbot pages as duplicates. For better readability and usability, all pages are restructured and enhanced by code examples or improved description texts. |
Overview
The Tocbot API is the set of options and methods you use from JavaScript to configure and control a table of contents. In J1 Template you usually do not call this API directly. Instead, you write a few YAML settings and the J1 toccer adapter (~/assets/theme/j1/adapter/js/toccer.js) builds the JavaScript configuration for you. Reading this manual is still useful, because all YAML keys map one-to-one to the API names described below.
Tocbot does three things, over and over again, while a page is open:
-
Parse — collect all headings from the content area and build a nested list (chapters and sub-chapters) from their heading levels.
-
Render — create the HTML of the table of contents (nested
ol/ullists with links) and place it into the TOC container element. -
Update — watch the scroll position of the page and mark the link of the top-most visible heading as active; collapse and expand nested sections as needed.
Module files
The Tocbot core used by J1 is split into small ES modules. Each file has one job. You do not need to touch these files, but knowing what they do helps when reading the rest of this manual.
| File | Description | ||
|---|---|---|---|
| The outer wrapper (UMD pattern). It loads the Tocbot core and makes it available globally as | ||
| The central index of the Tocbot core. Exports the public methods | ||
| All default settings of Tocbot in one place. Every option you can pass to | ||
| Parses the content. Selects all headings that match the | ||
| Builds and updates the DOM. Renders the nested heading tree as | ||
| Keeps the TOC container itself in sync with the page: when the TOC list is longer than its container, the container is scrolled so the active entry stays visible. | ||
| Tocbot’s built-in smooth scrolling for in-page links.
|
The Toccer adapter
The file ~/assets/theme/j1/adapter/js/toccer.js is a Liquid template that Jekyll turns into plain JavaScript at build time. The adapter:
-
reads the default settings from
_data/modules/defaults/toccer.yml, -
merges the user settings from
_data/modules/toccer.ymlon top, -
merges optional per-page settings from the page front matter on top of both,
-
waits until the J1 core has finished, the page content is visible, and the TOC is enabled for the current page,
-
waits until the TOC container (
#toc_mmenu) has been loaded into the page (the TOC panel is injected by AJAX), -
finally calls
tocbot.init(…)with the merged options.
The merge order is important. It is the same three-layer inheritance used by all J1 modules:
defaults (toccer.yml) <-- user settings (toccer.yml) <-- page front matterA key set in a later layer always wins over the same key set in an earlier layer.
| The adapter starts Tocbot only on pages where the table of contents is switched on: the merged option |
| Both wait phases of the adapter are time-bounded. If the page never becomes ready (5 seconds) or the TOC panel |
HTML Layout
Tocbot needs two elements on the page:
-
a content element that contains the headings — found by
contentSelector(default in J1:.js-toc-content), and -
an (empty) TOC container element where the generated table of contents is rendered — found by
tocSelector(default:.js-toc).
<!-- The element the TOC is generated FROM -->
<div class="js-toc-content">
<h2 id="section-1">Section 1</h2>
<p>...</p>
<h3 id="section-1-1">Section 1.1</h3>
<p>...</p>
<h2 id="section-2">Section 2</h2>
<p>...</p>
</div>
<!-- The element the TOC is rendered INTO -->
<div class="js-toc"></div>| Every heading needs an ID. The links of the table of contents point to the heading IDs ( |
To exclude a single heading from the table of contents, add the class configured as ignoreSelector (default in J1: .notoc):
<h2 id="internal-notes" class="notoc">Internal notes</h2>| In J1 Template you normally do not write this markup yourself. The page layouts already provide the content wrapper and the TOC panel ( |
Initialization
When the HTML portion is in place, Tocbot is initialised like so:
tocbot.init(options) // initialize tocbot with options-
options— object with Tocbot parameters. Optional. Every key you do not set falls back to its default value (see Parameters).
tocbot.init({
tocSelector: '.js-toc',
contentSelector: '.js-toc-content',
headingSelector: 'h2, h3, h4',
collapseDepth: 3,
});Different from libraries like Swiper, Tocbot is a singleton: there is only one table of contents per page. You do not create instances with new; you call init() on the global tocbot object. Calling init() again first destroys the current TOC and then builds a new one.
Initialization in J1 Template
In a J1 site the call above is generated by the Toccer adapter from your YAML configuration. The adapter:
-
waits until the J1 core is initialised and the page content is visible,
-
waits until the TOC panel (
#toc_mmenu) has been injected by AJAX, -
merges the YAML defaults, user settings and page front matter into a single options object,
-
calls
tocbot.init(…)with the merged options.
Two things are handled differently in J1 than in a stock Tocbot setup:
-
Smooth scrolling is delegated to J1. The adapter starts Tocbot with
scrollSmooth: falseand passes anonClickhandler instead. When a TOC link is clicked, the handler pushes the anchor URL to the browser’s history (history.pushState) and then scrolls to the heading using the central J1 scroller (j1.scrollToAnchor). This ensures all pages of a J1 site scroll the same way. -
The active link color comes from YAML. The (J1-specific) option
activeLinkColorstyles the highlighted TOC entry; it is not part of the original Tocbot library.
After initialization, the merged options are stored on the adapter and can be inspected in the browser console:
j1.adapter.toccer.moduleOptions // the effective Toccer optionsParameters
The Tocbot API offers a collection of parameters that allow you to configure almost every aspect of the table of contents. A parameter is just a key/value pair you pass to tocbot.init() (or, in J1 Template, write in the Toccer YAML configuration).
tocbot.init({
tocSelector: '.js-toc',
headingSelector: 'h2, h3, h4',
collapseDepth: 3,
});This section lists all available parameters in alphabetical order. Each parameter gets its own subsection with a short description and, where helpful, a code example. The accepted value types and the default value are summarised in a small table at the end of each subsection.
| The defaults listed below are the Tocbot library defaults. The J1 Template overrides several of them in its YAML configuration — for example, |
activeLinkClass
Class added to the active link — the link that corresponds to the top-most heading currently visible on the page. Use this class in your CSS to style the highlighted TOC entry.
| Name | Type | Default |
|---|---|---|
| string | 'is-active-link' |
activeListItemClass
Class added to the list item (li) that contains the active link.
| Name | Type | Default |
|---|---|---|
| string | 'is-active-li' |
basePath
Sets a base path that is put in front of every generated link. Useful if you use a <base> tag in the <head> of your page, because then plain #anchor links would point to the base URL instead of the current page.
| Name | Type | Default |
|---|---|---|
| string | '' |
bottomModeThreshold
Distance (in pixels) from the bottom of the page at which the bottom mode is enabled. Bottom mode handles the highlighting of headings near the end of the page that can never be scrolled to the top of the window (because there is not enough content below them).
| Name | Type | Default |
|---|---|---|
| number | 30 |
collapseDepth
Specifies how many heading levels should not be collapsed (are always displayed). For example, a value of 6 shows everything (there are only six heading levels, h1 .. h6), while 0 collapses all nested levels. The hidden sections open and close automatically (accordion effect) as the visitor scrolls through the matching content.
tocbot.init({
// always show two levels, collapse deeper levels
collapseDepth: 2,
});| Name | Type | Default |
|---|---|---|
| number | 0 |
collapsibleClass
Class added to a nested list that can be collapsed (but is not necessarily collapsed right now).
| Name | Type | Default |
|---|---|---|
| string | 'is-collapsible' |
contentElement
DOM node of the content element the headings are taken from. You can pass this instead of contentSelector if you already have a reference to the element.
tocbot.init({
contentElement: document.getElementById('content'),
});| Name | Type | Default |
|---|---|---|
| HTMLElement | null | null |
contentSelector
CSS selector of the content element, typically your content area, from which the headings are taken to calculate the TOC.
| Name | Type | Default |
|---|---|---|
| string | '.js-toc-content' |
disableTocScrollSync
Only takes effect when the TOC container itself is scrollable. By default, the container is scrolled automatically so the active entry stays visible (scroll sync). Set this option to true to switch that behaviour off.
| Name | Type | Default |
|---|---|---|
| boolean | false |
enableUrlHashUpdateOnScroll
When enabled, the URL hash (the part after #) is updated with the ID of the current heading while the visitor scrolls the page. This makes the browser URL always point to the section currently being read.
| Browsers limit how often |
| Name | Type | Default |
|---|---|---|
| boolean | false |
extraLinkClasses
Extra classes to add to all links of the table of contents, for example utility classes of your CSS framework.
| Name | Type | Default |
|---|---|---|
| string | '' |
extraListClasses
Extra classes to add to all lists (ol/ul) of the table of contents.
| Name | Type | Default |
|---|---|---|
| string | '' |
fixedSidebarOffset
Scroll position (in pixels) after which the positionFixedClass is added to the element selected by positionFixedSelector. The default 'auto' uses the TOC element’s own distance from the top of the document, so the sidebar becomes fixed exactly when it would leave the screen.
| Name | Type | Default |
|---|---|---|
| 'auto' | number | 'auto' |
hasInnerContainers
Set this to true when your headings are placed inside relative or absolute positioned containers within the content. Tocbot then adds up the offsets of all parent containers to calculate the correct position of each heading.
| Name | Type | Default |
|---|---|---|
| boolean | false |
headingLabelCallback
Optional callback to change the label of a heading before it is written to the TOC. For example, it can be used to shorten multi-line headings and add an ellipsis (…). The function is called for every heading, receives the label as a string, and must return the (modified) label.
tocbot.init({
headingLabelCallback: (label) => {
return label.length > 40 ? label.slice(0, 40) + '…' : label;
},
});| Alternatively, the attribute |
| Name | Type | Default |
|---|---|---|
| false | function(string): string | false |
headingObjectCallback
Optional callback to modify the parsed heading object before it is added to the TOC tree. The heading element is passed in the node parameter, the parsed data in the obj parameter. The function must return the same or a modified object. If nothing is returned, the heading is excluded from the TOC.
tocbot.init({
headingObjectCallback: (obj, node) => {
// skip headings marked with data-draft
if (node.dataset.draft !== undefined) return;
return obj;
},
});| Name | Type | Default |
|---|---|---|
| null | function(object, HTMLElement): object | void | null |
headingSelector
Which headings to grab inside of the content element to build the table of contents. A comma-separated list of heading selectors.
tocbot.init({
headingSelector: 'h2, h3, h4',
});| Name | Type | Default |
|---|---|---|
| string | 'h1, h2, h3' |
headingsOffset
Offset (in pixels) between the headings and the top of the document. This value is meant for minor adjustments of the highlighting: it shifts the point at which a heading counts as "reached" while scrolling.
| Name | Type | Default |
|---|---|---|
| number | 1 |
ignoreHiddenElements
When enabled, headings that are hidden in the DOM (not visible, no height) are skipped and do not appear in the table of contents.
| Name | Type | Default |
|---|---|---|
| boolean | false |
ignoreSelector
Headings that match the ignore selector are skipped and do not appear in the table of contents. In J1 Template the class .notoc is used for this purpose.
| Name | Type | Default |
|---|---|---|
| string | '.js-toc-ignore' |
includeHtml
Set to true to include the HTML markup from the heading node in the TOC link, instead of just its plain text. Useful when your headings contain inline elements (icons, code, keyboard keys) that should also show up in the table of contents.
| Name | Type | Default |
|---|---|---|
| boolean | false |
includeTitleTags
Automatically sets the HTML title attribute of each TOC link to the heading text. This can be useful for SEO purposes or when TOC titles are truncated by CSS, because the full text then appears as a tooltip.
| Name | Type | Default |
|---|---|---|
| boolean | false |
isCollapsedClass
Class that gets added to a nested list when it is currently collapsed (hidden).
| Name | Type | Default |
|---|---|---|
| string | 'is-collapsed' |
linkClass
Main class added to all links in the table of contents.
| Name | Type | Default |
|---|---|---|
| string | 'toc-link' |
listClass
Main class added to all lists (ol/ul) of the table of contents.
| Name | Type | Default |
|---|---|---|
| string | 'toc-list' |
listItemClass
Class added to all list items (li) of the table of contents.
| Name | Type | Default |
|---|---|---|
| string | 'toc-list-item' |
onClick
Function applied to all links in the TOC. It is called with the click event as the first parameter and can be used to stop propagation, prevent the default action, or perform your own action.
tocbot.init({
onClick: (event) => {
console.log('TOC link clicked:', event.currentTarget.href);
},
});| The J1 Toccer adapter uses this hook to push the anchor URL to the browser’s history and to scroll to the target heading with the central J1 scroller ( |
| Name | Type | Default |
|---|---|---|
| function(Event) | function () {} |
orderedList
Set to false to generate unordered lists (ul) instead of ordered lists (ol) for the table of contents.
| Name | Type | Default |
|---|---|---|
| boolean | true |
positionFixedClass
Fixed-position class that is added to the element selected by positionFixedSelector after the page has been scrolled down past the fixedSidebarOffset. Use it in your CSS to make a TOC sidebar stick to the screen.
| Name | Type | Default |
|---|---|---|
| string | 'is-position-fixed' |
positionFixedSelector
CSS selector of the element the positionFixedClass should be added to. Set this option to enable the fixed-sidebar behaviour; leave it at null to disable it.
| Name | Type | Default |
|---|---|---|
| string | null | null |
scrollContainer
CSS selector of a fixed article scroll container. Set this option if your content does not scroll with the page itself, but inside its own scrollable element. Tocbot then listens for scroll events on that element and uses it for all offset calculations.
| Name | Type | Default |
|---|---|---|
| string | null | null |
scrollEndCallback
Callback fired when scrolling ends (the scroll position no longer changes). The function receives the scroll event as its parameter.
| Name | Type | Default |
|---|---|---|
| function(Event) | function () {} |
scrollHandlerTimeout
Delay (in milliseconds) of the scroll handler. Together with scrollHandlerType, this option controls how often Tocbot reacts to scroll events.
| Name | Type | Default |
|---|---|---|
| number | 50 |
scrollHandlerType
Type of scroll handler to use so the scroll event does not fire too rapidly. Options are 'debounce', 'throttle', or 'auto':
-
debounce— wait until scrolling pauses, then update once. -
throttle— update at most once perscrollHandlerTimeout. -
auto— use debounce when the timeout is below 333 ms, otherwise use throttle. The reason is a limit in iOS browsers: they cannot callhistory.pushState()more than 100 times per 30 seconds.
| Name | Type | Default |
|---|---|---|
| 'auto' | 'debounce' | 'throttle' | 'auto' |
scrollSmooth
Enables Tocbot’s built-in smooth scrolling for TOC links.
| In J1 Template this option is always forced to |
| Name | Type | Default |
|---|---|---|
| boolean | true |
scrollSmoothDuration
Duration (in milliseconds) of Tocbot’s built-in smooth scroll animation. Only effective when scrollSmooth is enabled.
| Name | Type | Default |
|---|---|---|
| number | 420 |
scrollSmoothOffset
Offset (in pixels) applied to the target position of the built-in smooth scroll. Use a negative value if a fixed header covers the heading after scrolling. Only effective when scrollSmooth is enabled.
| Name | Type | Default |
|---|---|---|
| number | 0 |
skipRendering
Prevents the TOC DOM rendering if the table of contents is already rendered by an external system (for example, generated server-side). Tocbot then only takes care of highlighting and collapsing.
| Name | Type | Default |
|---|---|---|
| boolean | false |
throttleTimeout
Timeout (in milliseconds) between events firing to make sure updates do not happen too rapidly (for performance reasons). This is the legacy option; newer configurations should prefer scrollHandlerTimeout, which wins if both are set.
| Name | Type | Default |
|---|---|---|
| number | 50 |
tocElement
DOM node of the TOC container element. You can pass this instead of tocSelector if you already have a reference to the element.
| Name | Type | Default |
|---|---|---|
| HTMLElement | null | null |
tocScrollingWrapper
Element (not a selector!) of an outer scrolling wrapper that contains the TOC, for example a navigation panel with a search box on top. If set to null, the tocElement/tocSelector element itself is used for the TOC scroll sync. Only effective if disableTocScrollSync is false.
| Name | Type | Default |
|---|---|---|
| HTMLElement | null | null |
tocScrollOffset
Offset (in pixels) for the TOC scroll (top) position when scrolling the page. Keeps a bit of space above the active entry when the TOC container is scrolled automatically. Only effective if disableTocScrollSync is false.
| Name | Type | Default |
|---|---|---|
| number | 30 |
tocSelector
CSS selector of the element where to render the table of contents.
| Name | Type | Default |
|---|---|---|
| string | '.js-toc' |
Methods
A method is a function you can call on the global tocbot object to make it do something at runtime — build the table of contents, remove it, or rebuild it after the content has changed.
tocbot.init({ ... }); // build the TOC
tocbot.refresh(); // rebuild it (e.g. after content changed)
tocbot.destroy(); // remove it| Name | Description |
|---|---|
| Initialise Tocbot and build the table of contents.
If a TOC already exists, it is destroyed first (an internal |
| Remove the generated table of contents from the TOC container and detach all scroll, resize and click listeners. Use this before removing the content area from the page, or when the TOC is no longer needed. |
| Destroy and re-initialise Tocbot in one call.
Call this after the content has changed at runtime (for example after loading additional sections by AJAX), so the table of contents matches the new headings. |
Internal exports (for testing)
For testing purposes, the Tocbot index module additionally exports a few internal objects. They are not part of the public API and may change between versions; do not build features on top of them.
| Name | Description |
|---|---|
| The merged options object of the last |
| The internal DOM builder/updater (see |
| The internal content parser (see |
| The flat array of headings collected from the content element. |
| The (debounced or throttled) scroll handler that updates the TOC. |
YAML Configuration
In J1 Template, Toccer is configured by YAML files — no JavaScript required. Two files are involved, plus an optional third layer in the page front matter:
| File | Purpose |
|---|---|
| Default settings of the module (key |
| User settings (key |
Page front matter | Per-page overrides. Settings placed here win over both files, but only for the current page. |
_data/modules/toccer.yml)settings:
enabled: true
log: falseresource_options:
- toccer:
collapseDepth: 2Options
The table below lists the YAML keys of the Toccer module and their J1 default values. Most keys map one-to-one to the Tocbot parameters described above; the keys enabled, log and activeLinkColor are J1 additions.
| Name | Type | Default | Description |
|---|---|---|---|
| boolean | false | Enables or disables the Toccer module. The module defaults to disabled; it is switched on in the user settings of the J1 starter site. |
| boolean | false | Setting the log option to |
| string | The element where to render the table of contents. See tocSelector. | |
| string | The content area from which the headings are taken. See contentSelector. | |
| string | "h2, h3, h4, h5, h6" | Which headings to grab inside of the content element. Note that the J1 default excludes |
| string | Headings that match this class are skipped. Add the class | |
| integer | 3 | How many heading levels are always displayed (not collapsed). See collapseDepth. |
| string (color) | var(--bs-red) | Color of the TOC entry that is marked as selected (active). Accepts any CSS color value, including CSS variables. J1 addition — not part of the original Tocbot library. |
| integer | 150 | Timeout between events firing to make sure updates are not too rapid (for performance reasons). See throttleTimeout. |
| boolean | true | Smooth scrolling for TOC links. Note: the effect is produced by the central J1 scroller module; Tocbot’s built-in smooth scrolling stays disabled either way. |
| integer | 300 | Overall time (in milliseconds) to complete the scroll. |
| integer | 0 | Amount of space (in pixels) between the top of the page and the selected heading after the page has been scrolled. |
| string | null | null | CSS selector of a fixed article scroll container, if the content scrolls inside its own element. See scrollContainer. |
CSS Classes
Tocbot generates plain, unstyled HTML lists and marks them with CSS classes. All visual styling — colors, indentation, the accordion transitions — is done in CSS. The classes below are the ones used by the J1 Template (they are the Tocbot defaults; the class names are configurable via the parameters).
| Class | Applied to |
|---|---|
| Every generated list ( |
| Every list item ( |
| Every link ( |
| The link of the currently active heading (the top-most heading visible on the page). |
| The list item that contains the active link. |
| A nested list that can be collapsed. |
| A nested list that is currently collapsed (hidden). |
| The sidebar element, after the page has been scrolled past the |
<div class="js-toc">
<ol class="toc-list">
<li class="toc-list-item is-active-li">
<a href="#section-1" class="toc-link node-name--H2 is-active-link">Section 1</a>
<ol class="toc-list is-collapsible">
<li class="toc-list-item">
<a href="#section-1-1" class="toc-link node-name--H3">Section 1.1</a>
</li>
</ol>
</li>
<li class="toc-list-item">
<a href="#section-2" class="toc-link node-name--H2">Section 2</a>
</li>
</ol>
</div>| Each link additionally carries a class |