@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
372 lines (311 loc) • 11.3 kB
Markdown
---
title: 'Heading'
description: 'The Heading component is a helper to create automated semantic headings within a boundary of some rules.'
version: 10.104.0
generatedAt: 2026-04-17T18:46:09.796Z
checksum: 400a63665aa7aca0b3826acdfea84d1ee954466136ea1f63030445e5fe2760db
---
```tsx
import { Heading } from '@dnb/eufemia'
```
The Heading component is a helper to create automated semantic headings within a boundary of the web heading rules.
> Basically, only assistive technologies do need semantic headings. But they need them correct.
- [Source code](https://github.com/dnbexperience/eufemia/tree/main/packages/dnb-eufemia/src/components/heading)
- [Docs code](https://github.com/dnbexperience/eufemia/tree/main/packages/dnb-design-system-portal/src/docs/uilib/components/heading)
How does it work? The heading leveling is handled synchronously. But you can easily isolate one level, or a part by using a context provider: `<Heading.Level ...`. This allows you to later, asynchronous, add new headings inside. You can nest several contexts inside each.
The first code example is without using context provider. To handle levels in batches or asynchronous, use a `Heading.Level` context provider.
```tsx
render(
<Heading.Level reset={1}>
<Heading>h1</Heading>
<Heading>h2</Heading>
<Heading increase>h3</Heading>
<Heading>still h3</Heading>
<Heading increase>h4</Heading>
<Heading increase>h5</Heading>
<Heading decrease>h4</Heading>
<Heading level={2}>back to h2</Heading>
<Heading increase>h3</Heading>
</Heading.Level>
)
```
**NB:** Instead of `increase` and `decrease` you can use `up` and `down` as well.
### Heading level core-concept
- A **heading** will inherit the level from its previous sibling.
- A **level provider** will create an isolated level context (`Heading.Level`).
- A heading, nested inside a context (`Heading.Level`) will likewise inherit the previous context level.
- A heading can have a set of different [size](/uilib/elements/heading#headings) properties. More details below.
### Defining heading styles / sizes
For the visual part, we simply use [typography styles](/uilib/elements/heading) with the `size` property, e.g. `size="x-large"`
```tsx
render(
<Heading.Level reset={2}>
<Heading increase size="xx-large">
h3, but looks like h1
</Heading>
</Heading.Level>
)
```
### Heading level rules and corrections
The correction will ensure that:
1. a heading will start with a level **1**.
1. the second level will get corrected be level **2**.
1. if a level will increase with a factor of more than one (level=\{>1\}), it will get corrected to only increase by one (**1**).
1. if a level will be set to **1** a second time, it will get corrected to level **2**.
You get a `console.warn` warning (only in development) about corrections. You can attach a custom warning / handler if you need that: `<Heading.Level debug={(...logs) => console.info(...logs)}>`
You can also disable corrections by using the property `skip_correction={true}`.
In order to control leveling of headings systematically, you can make use of the `Heading.Level`, `Heading.Increase` or `Heading.Decrease` providers.
They are completely optional. But can help out to solve some kinds of challenges or logic.
```tsx
render(
<Heading.Level reset={1}>
<Heading>h1</Heading>
<Heading.Level level="2">
<Heading>h2</Heading>
<Heading increase>h3</Heading>
<Heading>still h3</Heading>
<Heading.Increase>
<Heading>h4</Heading>
<Heading>still h4</Heading>
</Heading.Increase>
</Heading.Level>
</Heading.Level>
)
```
### Skip auto correction and warnings
First, warnings will not show up in production builds. And to skip the auto correction of heading levels, simply use the `skip_correction` property.
### Heading levels interceptor modification
```js
import { resetLevels, setNextLevel } from '@dnb/eufemia/components/Heading'
// e.g. during Gatsby route change
export const onRouteUpdate = () => {
resetLevels(1)
// You can also call this method like this:
Heading.resetLevels(1)
}
// e.g. if you for some reason have to force setting a new level (Heading.setNextLevel)
setNextLevel(3)
```
**Limitations:** `resetLevels` and `setNextLevel` does not change contexts with an entry level higher than one (1).
In order to change also contexts, you can set `overwriteContext` to true:
```js
Heading.resetLevels(1, { overwriteContext: true })
Heading.setNextLevel(4, { overwriteContext: true })
```
#### Heading and routers
In order to reset the leveling during a page transition on using `react-router-dom` v5, you can make use of `withRouter`.
In v6 or `@reach/router`, you just call it in the correct "page" component.
You could additionally define "what is a page change" and what not, by using the `location: { pathname }` property you get inside these routing components.
You may still consider of using the basic elements. But keep in mind, you have to define headings responsibly.
```tsx
render(
<article>
<H1 size="large">h1</H1>
<H2 size="xx-large">h2</H2>
</article>
)
```
## Demos
**NB:** All the demos do use `<Heading.Level reset={1} ...`. This way every demo does reset the global level handling. You do not need that in your app.
```tsx
render(
<Style>
<ComponentBox data-visual-test="heading-default">
<Heading.Level debug reset={1}>
<Heading>h1</Heading>
<Heading>h2</Heading>
<Heading increase>h3</Heading>
<Heading increase>h4</Heading>
<Heading decrease>h3</Heading>
<Heading level="2" size="x-large">
h2
</Heading>
<Heading skip_correction level={4}>
h4
</Heading>
</Heading.Level>
</ComponentBox>
</Style>
)
```
### Heading level context
```tsx
render(
<Style>
<ComponentBox data-visual-test="heading-context">
<Heading.Level debug reset={1}>
<Heading>h1</Heading>
<Heading>h2</Heading>
<Heading.Increase>
<Heading>h3</Heading>
<Heading>h3</Heading>
</Heading.Increase>
<Heading inherit>h3</Heading>
<Heading.Decrease inherit>
<Heading>h2</Heading>
<Heading>h2</Heading>
<Heading increase>h3</Heading>
<Heading>h3</Heading>
</Heading.Decrease>
</Heading.Level>
</ComponentBox>
</Style>
)
```
### Level isolation
```tsx
render(
<Style>
<ComponentBox>
{() => {
const App = () => {
const [showHeading, setShowHeading] = React.useState(false)
return (
<Heading.Level debug reset={1}>
<Heading>h1</Heading>
<Heading>h2</Heading>
<Heading.Increase>
<ToggleButton
text="Toggle h3"
checked={showHeading}
onChange={() => setShowHeading((c) => !c)}
/>
{showHeading && (
<>
<Heading>h3</Heading>
<Heading>h3</Heading>
<Heading>h3</Heading>
</>
)}
</Heading.Increase>
<Heading.Level>
<Heading>h2</Heading>
</Heading.Level>
</Heading.Level>
)
}
return <App />
}}
</ComponentBox>
</Style>
)
```
```tsx
render(
<Style>
<ComponentBox data-visual-test="heading-mixin">
<Heading.Level debug reset={1}>
<Heading>h1</Heading>
<Heading>h2</Heading>
<H3 level="use">Increase to h3</H3>
<Heading>h3</Heading>
</Heading.Level>
</ComponentBox>
</Style>
)
```
## Properties
```json
{
"props": {
"text": {
"doc": "A heading, can be text or React.Node.",
"type": "React.Node",
"status": "optional"
},
"children": {
"doc": "A heading, can be text or React.Node.",
"type": "React.Node",
"status": "optional"
},
"size": {
"doc": "Define the typography [font-size](/uilib/typography/font-size) by a size _type_, e.g. `x-large`. Defaults to the predefined heading sizes.",
"type": [
"xx-large",
"x-large",
"large",
"medium",
"basis",
"small",
"x-small"
],
"status": "optional"
},
"level": {
"doc": "Overwrite the automated level handling to use a specific value to ensure correct level hierarchy.",
"type": ["1", "2", "3", "4", "5", "6"],
"status": "optional"
},
"increase": {
"doc": "If set to `true`, the heading level will be incremented by 1.",
"type": "boolean",
"status": "optional"
},
"decrease": {
"doc": "If set to `true`, the heading level will be decremented by 1.",
"type": "boolean",
"status": "optional"
},
"inherit": {
"doc": "If set to `true`, the heading last used level will be inherited. Also from inside a level context.",
"type": "boolean",
"status": "optional"
},
"reset": {
"doc": "If set to `true`, the heading level will be reset to 2. You can give it a custom level if you need to, e.g. `reset(1)`.",
"type": ["boolean", "number"],
"status": "optional"
},
"skip_correction": {
"doc": "If set to `true`, the heading will not be corrected and warnings will not be shown. Warnings do not show up in **production builds** else either",
"type": "boolean",
"status": "optional"
},
"debug": {
"doc": "If set to `true`, the content will have a prefix, showing the heading level.",
"type": ["boolean", "function"],
"status": "optional"
},
"debug_counter": {
"doc": "If set to `true`, the content will have both a prefix and a JSON log attached to both headings and level contexts.",
"type": ["boolean", "function"],
"status": "optional"
},
"element": {
"doc": "Define what HTML element should be used. If you use, e.g. a `span`, then `role=\"heading\"` and `aria-level` gets set. Defaults to semantic heading element.",
"type": ["string", "React.Element"],
"status": "optional"
},
"skeleton": {
"doc": "If set to `true`, an overlaying skeleton with animation will be shown.",
"type": "boolean",
"status": "optional"
},
"proseMaxWidth": {
"doc": "Sets the maximum width based on character count. This will limit the text width to approximately the specified number of characters. Use `true` for a default value of 60ch.",
"type": ["number", "boolean"],
"status": "optional"
},
"[Space](/uilib/layout/space/properties)": {
"doc": "Spacing properties like `top` or `bottom` are supported.",
"type": ["string", "object"],
"status": "optional"
}
}
}
```
Properties which do apply to the provider (level context) `Heading.Level` as well:
- `increase`
- `decrease`
- `inherit`
- `reset`
- `skip_correction`
- `debug`