Skip to content

thedigitalman/eleventy-plugin-toc

 
 

Repository files navigation

eleventy-plugin-toc-a11y

This Eleventy (11ty) plugin generates a table of contents (TOC) from page headings using an Eleventy filter.

It adds a navigation landmark with a heading and ARIA role to make it accessible[1] [2]. And creates a nested list of headings by level.

Markdown

# Fruits

## Apples

### Empire

### Fuji

### Pink Lady

## Pears

### Bartlett

### Bosc

### Starkrimson

HTML

<nav class="nav-toc" role="navigation" aria-labelledby="nav-toc">
  <h2 class="nav-toc-heading" id="nav-toc">Table of contents</h2>
  <ol class="nav-toc-list">
    <li class="nav-toc-list-item">
      <a class="nav-toc-list-item-anchor" href="#apples">Apples</a>
      <ol class="nav-toc-list">
        <li class="nav-toc-list-item"><a class="nav-toc-list-item-anchor" href="#empire">Empire</a></li>
        <li class="nav-toc-list-item"><a class="nav-toc-list-item-anchor" href="#fuji">Fuji</a></li>
        <li class="nav-toc-list-item"><a class="nav-toc-list-item-anchor" href="#pink-lady">Pink Lady</a></li>
      </ol>
    </li>
    <li class="nav-toc-list-item">
      <a class="nav-toc-list-item-anchor" href="#oranges">Pears</a>
      <ol class="nav-toc-list">
        <li class="nav-toc-list-item"><a class="nav-toc-list-item-anchor" href="#bartlett">Bartlett</a></li>
        <li class="nav-toc-list-item"><a class="nav-toc-list-item-anchor" href="#bosc">Bosc</a></li>
        <li class="nav-toc-list-item"><a class="nav-toc-list-item-anchor" href="#starkrimson">Starkrimson</a></li>
      </ol>
    </li>
  </ol>
</nav>

Step 1: Installation

npm install @thedigitalman/eleventy-plugin-toc-a11y --save-dev

Step 2: Configuration

All headings must have an id attribute. The plugin uses the id attribute of the headings it finds to build the navigation.

You can do this manually, but using markdown-it and markdown-it-anchor make it easy.

Open your Eleventy config file (probably .eleventy.js), use addPlugin, and add some Markdown settings.

const eleventyPluginTOC = require( '@thedigitalman/eleventy-plugin-toc-a11y' );
const markdownIt = require( 'markdown-it' );
const markdownItAnchor = require( 'markdown-it-anchor' );

module.exports = function ( eleventyConfig ) {
  // Plugins
  eleventyConfig.addPlugin( eleventyPluginTOC );

  // Markdown settings
  eleventyConfig.setLibrary( 'md',
    markdownIt().use( markdownItAnchor )
  );
}

Step 3: Usage

All headings must be in proper order without skipping levels [3].

Open a layout template file and add the filter before your content. This gives you a good outline, and lets people review the TOC before reading the content.

Liquid

{{ content | toc }}

<main>
  {{ content }}
</main>

Nunjucks

Always include the safe filter when using Nunjucks.

{{ content | toc | safe }}

<main>
  {{ content | safe }}
</main>

Default Options

{
  tags: ['h2', 'h3', 'h4', 'h5', 'h6'],
  wrapper: 'nav',
  wrapperClass: 'nav-toc',
  heading: true,
  headingClass: 'nav-toc-heading',
  headingLevel: 'h2',
  headingText: 'Table of contents',
  listType: 'ol',
  listClass: 'nav-toc-list',
  listItemClass: 'nav-toc-list-item',
  listItemAnchorClass: 'nav-toc-list-item-anchor'
}
Option Data Type Description Notes
tags Object An array of heading levels to include in the TOC. Page titles (i.e. h1) should be excluded.
wrapper String The navigation landmark element of the TOC. In most cases use nav. If you replace it, be sure it’s valid HTML and accessible.
wrapperClass String The CSS class name for the TOC parent element. Using an empty string removes the class attribute.
heading Boolean Whether the TOC uses a heading element. Using heading text for sections helps everyone.
headingClass String The CSS class name for the TOC heading element. Using an empty string removes the class attribute.
headingLevel String The level of the TOC heading element. In most cases use h2, but you can use h2h6. If you replace it, be sure it’s valid HTML and accessible.
headingText String The TOC heading element text. Keep it concise and relevant.
listType String The type of list for navigation items. Use ol or ul. Other elements won’t work.
listClass String The CSS class name for the list. Using an empty string removes the class attribute.
listItemClass String The CSS class name for each list item. Using an empty string removes the class attribute.
listItemAnchorClass String The CSS class name for each anchor in a list item. Using an empty string removes the class attribute.

Override Default Options

You can override the default options in the Eleventy config file or inline.

Eleventy config file

eleventyConfig.addPlugin( pluginToC, {
  wrapperClass: 'toc',
  headingClass: 'toc-heading',
  headingText: 'Topics',
  listType: 'ul'
});

Inline (Liquid)

{{ content | toc(wrapperClass='toc',headingClass='toc-heading',headingText='Topics',listType='ul') }}

Inline (Nunjucks)

{{ content | toc(wrapperClass='toc',headingClass='toc-heading',headingText='Topics',listType='ul') | safe }}

References

  1. 4.3.6 Navigation | WAI-ARIA Authoring Practices 1.2 W3C
  2. Navigation Landmark: ARIA Landmark Example W3C ARIA Authoring Practices Task Force
  3. H42: Using h1-h6 to identify headings Techniques for WCAG 2.1

About

An 11ty plugin to generate an accessible table of contents from page headings using an 11ty filter.

Topics

Resources

Stars

Watchers

Forks

Languages

  • JavaScript 100.0%