On this page TOC TOC

The m3e-toc component generates a hierarchical table of contents for in-page navigation.

Installation
npm i @m3e/toc
Usage

This section outlines usage examples and configuration guidance for the components in this package.

Generating a TOC

The m3e-toc component automatically generates a table of contents by scanning heading elements (h1 through h6, and m3e-hading) within a specified container. It creates a navigable outline that reflects the document's structure, enabling users to quickly jump between sections.

To activate, set the for attribute to the ID of the container whose headings should be indexed. The generated TOC updates reactively as headings are added, removed, or reordered.

Headers having the m3e-toc-ignore attribute will be ignored by the TOC generator. This is typically used for page-level headings whose text is mirrored by the TOC's title.

<div id="d1">
  <m3e-toc for="d1">
    <span slot="overline">Overline</span>
    <span slot="title">Title</span>
  </m3e-toc>
  <div>
    <h2 id="h1">Heading 1</h2>
    <h3 id="h1.1">Heading 1.1</h3>
    <h4 id="h1.1.1">Heading 1.1.1</h4>
    <h3 id="h2">Heading 1.2</h3>
    <h2 id="h2.1">Heading 2</h2>
  </div>
</div>
Heading

Use the overline and title slots to provide heading content for a TOC. The overline is limited to a single line and the title is limited to two lines. If content overflows, it will be truncated with an ellipsis.

<m3e-toc for="d1">
    <span slot="overline">Overline</span>
    <span slot="title">Title</span>
  </m3e-toc>
Maximum depth

When generating a TOC, you can control the maximum depth of headers that appear in the TOC using the max-depth attribute. By default, the maximum depth is 2.

The heading depth is determined by the highest-level heading found within the container. For example, if no h1 is present but an h2 is, the depth starts at level 2.

Accessibility

The m3e-toc component is marked with role="navigation" to signal its purpose as a navigational landmark.

To ensure assistive technologies announce it meaningfully, TOCs should labeled using both the overline and title via aria-labelledby. This dual-labeling approach preserves expressive hierarchy—where the overline provides contextual framing (e.g., “On this page”) and the title conveys specific content.

Individual items are organized within an unordered list and given ARIA role="link" to convey their interactive nature to assistive technologies. Each item also receives tabindex="-1" to make it programmatically focusable without being included in the default tab order.

The active item receives aria-current="true" to indicate its current state within the document context. This attribute helps assistive technologies convey that the linked section is currently in view, enhancing orientation and navigational clarity for screen reader users.

Native module support

This package uses JavaScript Modules. To use it directly in a browser without a bundler, use a module script similar to the following.

<script type="module" src="/node_modules/@m3e/toc/dist/index.js"></script>

In addition, you must use an import map to include dependencies.

<script type="importmap">
  {
    "imports": {
      "lit": "https://cdn.jsdelivr.net/npm/lit@3.3.0/+esm",
      "@m3e/core": "/node_modules/@m3e/core/dist/index.js",
      "@m3e/core/a11y": "/node_modules/@m3e/core/dist/a11y.js"
    }
  }
</script>

For production, use index.min.js and a11y.min.js for faster load times.

API

This package includes a Custom Elements Manifest (custom-elements.json), which documents the properties, attributes, slots, events and CSS custom properties of each component.

You can explore the API below, or integrate the manifest into your own tooling.