Description
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.
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.
<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 its 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 properties. More details below.
Defining heading styles / sizes
For the visual part, we simply use typography styles with the size
property, e.g. size="x-large"
<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:
- a heading will start with a level 1.
- the second level will get corrected be level 2.
- if a level will increase with a factor of more than one (level={>1}), it will get corrected to only increase by one (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}
.
Heading level context provider / asynchronous
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.
<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>
TODO: Integration with the global Provider.
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
import { resetLevels, setNextLevel } from '@dnb/eufemia/components/Heading'// e.g. during Gatsby route changeexport 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:
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.
Basic heading elements
You may still consider of using the basic elements. But keep in mind, you have to define headings responsibly.
<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 don't need that in your app.
Default headings
[h1] h1
[h2] h2
[h3] h3
[h4] h4
[h3] h3
[h2] h2
[h4] h4
<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>
Heading level context
[h1] h1
[h2] h2
[h3] h3
[h3] h3
[h3] h3
[h2] h2
[h2] h2
[h3] h3
[h3] h3
<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>
Level isolation
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> ) } render(<App />)
SyntaxError: Unexpected token (1:3)
Combine with manual heading
[h1] h1
[h2] h2
Increase to h3
[h3] h3
<Heading.Level debug reset={1}> <Heading>h1</Heading> <Heading>h2</Heading> <H3 level="use">Increase to h3</H3> <Heading>h3</Heading> </Heading.Level>