npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@maxmmyron/rehype-section-headings

v1.3.0

Published

Wraps all heading elements and any following content with section tags

Readme

🎁 @maxmmyron/rehype-section-headings

A fork of Tim Perkins' great rehype package rehype-section-headings. I added a few customizable options that make it more suitable for my personal use cases.

CI

License: MIT

rehype plugin to wrap all heading elements and any following content with <section> tags

Installation

# npm
npm install @maxmmyron/rehype-section-headings

# yarn
yarn add @maxmmyron/rehype-section-headings

# pnpm
pnpm add @maxmmyron/rehype-section-headings

Usage

import rehype from "rehype";
import rehypeSectionHeadings from "@maxmmyron/rehype-section-headings";

rehype().use(rehypeSectionHeadings).process(/* html */);

Example

The following script..

import rehype from "rehype";
import rehypeSectionHeadings from "@maxmmyron/rehype-section-headings";

const html = `
<h1>Heading level 1</h1>
<p>Hey, World!</p>
<span>This shouldn't <i>span</i> the whole page</span>
<h2>Heading level 2</h2>
<p>Hello again, world!</p>
`;

rehype().use(rehypeSectionHeadings).process(html);

...results in the following output

<section>
  <h1>Heading level 1</h1>
  <p>Hey, World!</p>
  <span>This shouldn't <i>span</i> the whole page</span>
</section>
<section>
  <h2>Heading level 2</h2>
  <p>Hello again, world!</p>
</section>

API

rehype().use(rehypeSectionHeadings, [options])

options

options.sectionDataAttribute

Type: string. Default: undefined.

If any heading elements have an id attribute, this plugin will take the data-* attribute name specified here and add it against any <section> tags.

The value of the data-* attribute will be the same as the heading elements id attribute.

import rehype from "rehype";
import rehypeSectionHeadings from "@maxmmyron/rehype-section-headings";

const html = `
<h1 id="heading-level-1">Heading level 1</h1>
<p>Hey, World!</p>
<span>This shouldn't <i>span</i> the whole page</span>
<h2 id="heading-level-2">Heading level 2</h2>
<p>Hello again, world!</p>
`;

rehype()
  .use(rehypeSectionHeadings, { sectionDataAttribute: "data-heading-id" })
  .process(html);

...results in the following output

<section data-heading-id="heading-level-1">
  <h1 id="heading-level-1">Heading level 1</h1>
  <p>Hey, World!</p>
  <span>This shouldn't <i>span</i> the whole page</span>
</section>
<section data-heading-id="heading-level-2">
  <h2 id="heading-level-2">Heading level 2</h2>
  <p>Hello again, world!</p>
</section>

options.maxHeadingLevel

Type: (1 | 2 | 3 | 4 | 5 | 6). Default: 6.

The maximum heading <h*> level to wrap in section tags. Any heading elements with a level higher than the specified value will be ignored and wrapped within the last section tag.

For example, a maxHeadingLevel of 2 will wrap all <h1> and <h2> elements in <section> tags, but any <h3> or higher elements will be ignored and wrapped within their corresponding <h2> section tag:

import rehype from "rehype";
import rehypeSectionHeadings from "@maxmmyron/rehype-section-headings";

const html = `
<h1>Heading level 1</h1>
<p>Hey, World!</p>
<p>This is a bit of content.</p>
<h2>Heading level 2</h2>
<p>What is the meaning of life?</p>
<h3>Heading level 3</h3>
<p>Lorem ipsum means nothing to me.</p>
<h2>Heading level 2 (again)</h2>
<p>A bit more content</p>
`;

rehype().use(rehypeSectionHeadings, { maxHeadingLevel: 2 }).process(html);

...results in the following output

<section>
  <h1>Heading level 1</h1>
  <p>Hey, World!</p>
  <p>This is a bit of content.</p>
</section>
<section>
  <h2>Heading level 2</h2>
  <p>What is the meaning of life?</p>
  <h3>Heading level 3</h3>
  <p>Lorem ipsum means nothing to me.</p>
</section>
<section>
  <h2>Heading level 2 (again)</h2>
  <p>A bit more content</p>
</section>

options.headerWrap

Type: Partial<Record<"h1" | "h2" | "h3" | "h4" | "h5" | "h6", string | Hast.Element>>. Default: {}.

An optional element to wrap a particular header in. Useful as a jumping-off point when you need to insert extra content with the header, while keeping the header itself as the first child of the section. Can be specified as a string (i.e. "div" or "aside"), or as a hast element (which provides more granular element property control).

import rehype from "rehype";
import rehypeSectionHeadings from "@maxmmyron/rehype-section-headings";

const html = `
<h1>Heading level 1</h1>
<p>Hey, World!</p>
<p>This is a bit of content.</p>
<h2>Heading level 2</h2>
<p>What is the meaning of life?</p>
`;

rehype()
  .use(rehypeSectionHeadings, { headerWrap: { h1: "aside" } })
  .process(html);

...results in the following output

<section>
  <aside>
    <h1>Heading level 1</h1>
  </aside>
  <p>Hey, World!</p>
  <p>This is a bit of content.</p>
</section>
<section>
  <h2>Heading level 2</h2>
  <p>What is the meaning of life?</p>
</section>

You can also use hast elements to describe the wrapping element:

import rehype from "rehype";
import rehypeSectionHeadings from "@maxmmyron/rehype-section-headings";

const html = `
<h1>Heading level 1</h1>
<p>Hey, World!</p>
<p>This is a bit of content.</p>
<h2>Heading level 2</h2>
<p>What is the meaning of life?</p>
`;

rehype()
  .use(rehypeSectionHeadings, {
    headerWrap: {
      h1: {
        type: "element",
        tagName: "aside",
        properties: { className: ["aside"] },
        children: [],
      },
    },
  })
  .process(html);

...results in the following output

<section>
  <aside class="aside">
    <h1>Heading level 1</h1>
  </aside>
  <p>Hey, World!</p>
  <p>This is a bit of content.</p>
</section>
<section>
  <h2>Heading level 2</h2>
  <p>What is the meaning of life?</p>
</section>

options.contentWrap

Type: string | Hast.Element. default: null.

An optional element to wrap the content of a section in. Useful as a jumping-off point when you need to further customize a section's content. Accepts either a string (i.e. a tag name like "div") or a hast Element.

import rehype from "rehype";
import rehypeSectionHeadings from "@maxmmyron/rehype-section-headings";

const html = `
<h1>Heading level 1</h1>
<p>Hey, World!</p>
<p>This is a bit of content.</p>
<img src="LK-99.png" alt="A supposed room-temperature superconductor." />
<h2>Heading level 2</h2>
<p>I want to believe!!!</p>
`;

rehype().use(rehypeSectionHeadings, { contentWrap: "main" }).process(html);

...results in the following output

<section>
  <h1>Heading level 1</h1>
  <main>
    <p>Hey, World!</p>
    <p>This is a bit of content.</p>
    <img src="LK-99.png" alt="A supposed room-temperature superconductor." />
  </main>
</section>
<section>
  <h2>Heading level 2</h2>
  <main>
    <p>I want to believe!!!</p>
  </main>
</section>

We can also provide this as a hast element, to get more granular control over the element's properties:

import rehype from "rehype";
import rehypeSectionHeadings from "@maxmmyron/rehype-section-headings";

const html = `
<h1>Heading level 1</h1>
<p>Hey, World!</p>
<p>This is a bit of content.</p>
<img src="LK-99.png" alt="A supposed room-temperature superconductor." />
<h2>Heading level 2</h2>
<p>I want to believe!!!</p>
`;

rehype()
  .use(rehypeSectionHeadings, {
    contentWrap: {
      type: "element",
      tagName: "main",
      properties: { className: ["content"] },
      children: [],
    },
  })
  .process(html);

...results in the following output

<section>
  <h1>Heading level 1</h1>
  <main class="content">
    <p>Hey, World!</p>
    <p>This is a bit of content.</p>
    <img src="LK-99.png" alt="A supposed room-temperature superconductor." />
  </main>
</section>
<section>
  <h2>Heading level 2</h2>
  <main class="content">
    <p>I want to believe!!!</p>
  </main>
</section>

We can even combine this with options.headerWrap to get even more control over the output:

import rehype from "rehype";

const html = `
<h1>Heading level 1</h1>
<p>Hey, World!</p>
<p>This is a bit of content.</p>
<img src="LK-99.png" alt="A supposed room-temperature superconductor." />
<h2>Heading level 2</h2>
<p>I want to believe!!!</p>
`;

rehype()
  .use(rehypeSectionHeadings, {
    headerWrap: {
      h1: "header",
      h2: {
        type: "element",
        tagName: "aside",
        properties: { className: ["aside"] },
        children: [],
      },
    },
    contentWrap: {
      type: "element",
      tagName: "main",
      properties: { className: ["content"] },
      children: [],
    },
  })
  .process(html);

...results in the following output

<section>
  <header>
    <h1>Heading level 1</h1>
  </header>
  <main class="content">
    <p>Hey, World!</p>
    <p>This is a bit of content.</p>
    <img src="LK-99.png" alt="A supposed room-temperature superconductor." />
  </main>
</section>
<section>
  <aside class="aside">
    <h2>Heading level 2</h2>
  </aside>
  <main class="content">
    <p>I want to believe!!!</p>
  </main>
</section>

License

MIT