Skip to content

About

⚛ Headings (h1–h6) computed from your React component tree, for accessibility and SEO.

Topics

Resources

Stars

86 stars

Watchers

1 watching

Forks

Repository files navigation

React Headings Logo

React Headings

Never write <h1>–<h6> again.

Hardcoded heading levels break accessibility and SEO when components are reused. React Headings fixes this by computing each level from your component tree.

Features

  • Supports server-side rendering
  • Only 369 bytes minified & brotlied
  • Typed with TypeScript
  • Works with any CSS solution (Tailwind, CSS-in-JS, etc.)
  • Plays nicely with component libraries

Install

npm install react-headings

Usage

Use Heading for every heading. Wrap the content that belongs under a heading in HeadingLevel: headings inside render one level deeper.

import { Heading, HeadingLevel } from "react-headings";

function Page() {
  return (
    <>
      <Heading>Star Wars</Heading> {/* <h1> */}
      <HeadingLevel>
        <Heading>Characters</Heading> {/* <h2> */}
        <HeadingLevel>
          <Section title="Luke" /> {/* <h3> */}
          <Section title="Leia" /> {/* <h3> */}
          <Section title="Han Solo" /> {/* <h3> */}
        </HeadingLevel>
      </HeadingLevel>
    </>
  );
}

function Section({ title, children }) {
  return (
    <section>
      <Heading>{title}</Heading>
      <HeadingLevel>{children}</HeadingLevel>
    </section>
  );
}

Section doesn't know its level: it renders <h3> here.

Dialogs

Portaled elements, like dialogs, aren't part of the page outline. Use level to start their headings at <h1>:

<Dialog>
  <HeadingLevel level={1}>
    <Heading>Delete file?</Heading> {/* <h1> */}
  </HeadingLevel>
</Dialog>

Styling

React Headings only picks the tag. Style headings however you like:

<Heading className="text-lg">Title</Heading>

Or use render for component libraries:

<Heading render={(props, { tag }) => <Text as={tag} size="lg" {...props} />}>
  Title
</Heading>

API

<Heading>

Renders <h1>, <h2>, <h3>, <h4>, <h5>, or <h6> based on the current level. <h1> by default.

Accepts every <h1> prop and a ref, plus:

Prop Type Description
render (props, { level, tag }) => ReactElement Renders your own element. Spread props on it (includes children and ref).

<HeadingLevel>

Moves the headings inside one level deeper.

Prop Type Default Description
offset number 1 Levels added to headings inside. Rarely used.
level number Level of headings inside, ignoring parents.

Pass offset or level, not both. Nested offsets add up. offset={0} adds nothing, which is useful for conditional nesting.

Invalid values never throw: they're ignored with a warning, as if not passed. null counts as not passed, without a warning.

useHeadingLevel()

Returns the level (1–6) and tag ("h1"–"h6") a Heading would render here.

Development warnings

In development, React Headings warns in the console when:

  • a level is skipped,
  • a level goes past 6,
  • an offset or level is invalid.

Warnings are removed from production builds. Vite and webpack show them automatically in dev mode. In plain Node, run with --conditions=development.

License

MIT

About

⚛ Headings (h1–h6) computed from your React component tree, for accessibility and SEO.

Topics

Resources

Stars

86 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages