rehype-autolink-headings

Rehype plugin that injects clickable anchor links into every heading with an id, so readers can share direct links to a section.

Library
npm
v7.1.0
267 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
38 /100 Needs Attention
Development Activity 0
Maintenance 20
Community 52
Maturity 60
Momentum 20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
66 /100 Good
Architecture 72
Code Quality 88
Innovation 45
Learning Curve 60

rehype-autolink-headings is a plugin for the unified/rehype content-transformation ecosystem that walks an HTML abstract syntax tree (hast) and adds a self-referencing link to every heading element that already has an id property. It looks for <h1> through <h6> elements, and for each one inserts an <a href="#id"> pointing back at itself, the same pattern used to generate the clickable heading anchors seen on GitHub and npm when rendering markdown.

The plugin is deliberately narrow in scope — it only links headings that already have ids, and is almost always paired with rehype-slug (which generates those ids from heading text) in a single unified pipeline. Its configuration surface covers five distinct link-placement behaviors (prepend, append, wrap, before, after), fully custom link/wrapper content via static hast nodes or a builder function, and fine-grained control over which headings qualify via a hast-util-is-element-compatible test.

What You Get

  • A single default-exported plugin function you register with unified().use() in a rehype pipeline
  • Five link-placement behaviors (prepend, append, wrap, before, after) selectable via one option
  • Full control over injected link/wrapper content, either as static hast nodes or a per-heading builder function
  • A test option (any hast-util-is-element test) to restrict which headings get linked, e.g. skip <h1>
  • Full TypeScript types for Options, Behavior, Build, and BuildProperties, published alongside the JS

Common Use Cases

  • Documentation sites piping content through rehype/remark add it after rehype-slug so every section heading becomes a shareable deep link
  • MDX-based blogs and content platforms use it to give generated tables of contents working in-page anchors
  • Teams wanting a link icon instead of plain text pass a content builder function (often built with hastscript) to render an SVG/icon span inside the anchor
  • API-reference and structured-docs generators use it so every rendered heading (method, class, section) is individually linkable for cross-referencing

Under The Hood

Architecture

The entire plugin lives in a single module, lib/index.js: rehypeAutolinkHeadings(options) runs once at pipeline-setup time to resolve configuration (behavior, content, group, test) and pick one of three visitor strategies — inject (prepend/append), around (before/after, with optional group wrapping), or wrap — then returns a transform that walks the hast tree once with unist-util-visit, matching elements via hast-util-heading-rank (is this a heading?) plus a required id property and the optional custom test. The design is a clean, single-responsibility functional module with no classes or internal layering — appropriate for its narrow scope, though it means all matching, dispatch, and node-construction logic sits in one file rather than being decomposed further.

Tech Stack

An ESM-only (type: module) package with a small, ecosystem-native dependency set: @types/hast (types only), @ungap/structured-clone (a deep-clone polyfill used when copying user-supplied content/group nodes), hast-util-heading-rank, hast-util-is-element, and unist-util-visit — all standard unified-project building blocks. There’s no separate compiled build step for the JS itself; types are authored via JSDoc and checked against a hand-written lib/types.d.ts using tsc plus type-coverage (configured to require 100% coverage). Linting/formatting run through xo (ESLint) and prettier, with remark-preset-wooorm for markdown-doc formatting.

Code Quality

Tests live in test/index.js using Node’s built-in node:test and node:assert, combining direct API-behavior assertions (custom content/group/properties/headingProperties functions) with a data-driven fixture suite — 14 fixture folders under test/fixtures/, each an input.html/output.html/optional config.json triple covering every behavior and option combination. Coverage is enforced via c8 --100 --check-coverage, and CI (.github/workflows/main.yml) runs the full test suite across two Node LTS versions with Codecov reporting. Combined with the 100%-required type-coverage check, this is a well-tested, strictly-typed small package.

What Makes It Unique

The plugin isn’t algorithmically novel — it’s a straightforward, single-pass AST transform — but it functions as the de facto standard solution within the unified/rehype ecosystem for heading-anchor links, designed to compose cleanly with rehype-slug and any other rehype/remark plugin in a pipeline. Its value is in the completeness of its configuration surface (five behaviors, arbitrary custom content/grouping, selective heading targeting) rather than in a new technique.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers