uberschrift ๐งข
GitHubZero-dependency magic heading levels for React and Vue.js
<Hx>I'm the h1!'</Hx>
<HxBoundary>
<Hx>I want to be an h2</Hx>
<HxBoundary>
<Hx>I will be an h3</Hx>
</HxBoundary>
</HxBoundary>
<h1>I'm the h1!'</h1>
<h2>I want to be an h2</h2>
<h3>I will be an h3</h3>
Motivation ๐คธ
Why heading levels (h1, h2, โฆ) matter ๐
Grouping text sections underneath headings adds a logical hierarchy to the contents of a page, contributing to both accessibility and search engine optimization (SEO). Heading elements, ranging from <h1>
to <h6>
, represent different levels of importance and organization.
Properly nesting these elements ensures that screen readers and other assistive technologies can interpret and convey the content's structure to users with visual impairments, enhancing accessibility. Additionally, search engines rely on heading tags to understand the content hierarchy and relevance, influencing how they index and rank the page.
Consistent and well-ordered heading levels not only improve the overall readability of the document for both users and search engines but also contribute to a more efficient and user-friendly browsing experience.
Here's an example of a DOM structure with incorrect heading order:
<h1>This is the page's main heading โ
</h1>
<h2>This is also fine โ
</h2>
<h4>This should have been preceded by an h3! โ</h4>
If you want to learn more about this, check out the article in our blog: Heading for Greatness โ A React Developer's Guide to HTML Headings!
Why is dealing with heading levels difficult? ๐คท
In React projects, component encapsulation often makes chosing the right heading level within these components hard. They are often nested in an unforeseeable way, so the heading you chose to be an <h3>
could now be used outside of the boundary of an <h2>
, messing up the order.
How does uberschrift help? ๐งข
uberschrift provides you with two components: one we call <Hx>
(as in "heading level x") that you should use for your headings; and one <HxBoundary>
that you use to structure your document. Within these boundaries, <Hx>
always choses the correct heading level. If you need to structure your document one level deeper, you wrap your component in a new <HxBoundary>
.
We're borrowing this idea from Tenon-UI โค๏ธ.
Usage ๐ ๏ธ
โ๏ธ React
npm install uberschrift
Example ๐
page.tsx
:
import { Hx, HxBoundary } from "uberschrift";
<Hx>Outside of the top level: this will be an h1</Hx>
<HxBoundary>
<Hx>Within the top level: this will be an h2</Hx>
<HxBoundary>
<Hx>Within the 2nd level: this will be an h3</Hx>
</HxBoundary>
</HxBoundary>
๐ฒ Vue.js
npm install vueberschrift
Example ๐
App.vue
:
<script setup lang="ts">
import { Hx, HxBoundary } from "vueberschrift";
</script>
<template>
<Hx>Outside of the top level: this will be an h1</Hx>
<HxBoundary>
<Hx>Within the top level: this will be an h2</Hx>
<HxBoundary>
<Hx>Within the 2nd level: this will be an h3</Hx>
</HxBoundary>
</HxBoundary>
</template>
FAQ ๐คฏ
How can I use it with my UI library? ๐ค
We have examples for Chakra UI and Material UI. Essentially you can either use the context hook useHx
(see below) or you can leverage Hx
into another component.
Example for Chakra:
import { Hx, HxBoundary } from "uberschrift";
import { Heading as ChakraHeading, HeadingProps } from "@chakra-ui/react";
const Heading = (props: HeadingProps) => <ChakraHeading {...props} as={Hx} />;
// โฆ
<Heading size="xl">โฆ</Heading>;
How does it handle heading elements nested below the 6th level? 7๏ธโฃ
The HTML Spec only allows h1 through h6 as elements and for most documents this should be more than enough.
That being said: if you find yourself nesting deeper, you can make that possible by leveraging WAI-ARIA attributes, e.g.: <div role="heading" aria-level="7">โฆ</div>
. uberschrift does that for you.
If you want to style these elements, you can do it like this:
[aria-level="7"] {
font-weight: bold;
}
How does it work under the hood? ๐
It's a simple use case of React Context: HxBoundary
is merely a nestable context provider, that increments the heading level.
In fact, you can use that context with useHx
if you need it:
import { useHx } from "uberschrift";
const {
Element, // string, e.g "h4"
level, // number => 4
} = useHx();
Sponsors โค๏ธ
Legal Notice, reactExample