Optimizing Headline Hierarchies for Improved Web Accessibility with Storyblok
Storyblok is the first headless CMS that works for developers & marketers alike.
Using headlines, so the <h>
elements, in a meaningful way is part of writing semantic code. Generally speaking, there should only be one <h1>
per page, ranks should not be skipped, and the respective h tags should be used for structuring. The <h>
tag's value conveys the content's relevance to a screen reader. People who use assistive tech might use the headlines to quickly browse an article to find what they are looking for.
Would you like to dive right in? Here is a link to the Github Repo with the examples we will discuss in this article.
Similarly, Google’s crawlers will fall back on the headlines to check whether content is relevant for a search request - making headline hierarchies crucial for search engine optimization.
Headline Hierarchies in a Headless CMS
A headless CMS like Storyblok gives you a lot of flexibility - both as a developer as well as a marketeer or editor. This is a great benefit of the system when we use it wisely. All the flexibility aside, you want to ensure the headline structure remains. Regardless of what bloks editors might use in a specific content type - you want to make sure this does not get in the way of semantically conveying the importance of different pieces of content. Let’s have a look at our different options.
We will have a look at:
- Manually determined headline hierarchies
- Headline text field
- Formatting headlines in rich text fields or markdown
- Automatically determined headline hierarchy
Using Markdown or Richtext for headline structures
In the rich text field type in Storyblok, you have many different options to style your text - one of them being adding markdown, another choosing between headlines from <h1> to <h6>.
This is the least recommended option from an accessibility perspective - even though it might be feasible under specific circumstances. Let’s explore a little bit, why: The freedom to use markdown or the headline options in the rich text field brings the risk of changing the markup in ways that negatively impact web accessibility. Since you want to make sure you stick to a meaningful landmark structure and headline hierarchy, it's only possible to keep a sufficient overview in a very small team or on a project with very little content.
For most teams, especially interdisciplinary, larger teams, it would be better to disable writing markdown altogether and strictly limit where headlines can be added through rich text fields. This way, you as a developer can ensure the website follows best practices and is optimized for all users and headline hierarchies follow the recommended guidelines.
Even with proper training, a small risk remains that headline structures are not maintained in the way they were intended. In Storyblok, you can leave a description below the field to highlight the importance of headline hierarchies, but human error can never fully be avoided.
Headline Text Fields
You could also approach the headline hierarchies from atomic design perspective: by adding an additional field to the bloks using headlines. You can use the “single option” field type and refer to an internal data source where you can define your headline levels.
In SvelteKit, we can set the tag dynamically by using the <svelte:element>
. To do so, we are defining headline_level
as a single-option field in our Teaser component, referencing the different headline levels as a data source (skipping H1, as we want to make sure there is only one H1 element per page) and then setting it dynamically through the this
prop.
This way, the headline rank will be controlled manually in Storyblok. Without pre-defined headline levels getting in the way, we can determine for each page what hierarchy a certain headline should have.
Automatically determined headline hierarchy
The option that would most securely ensure a semantically correct headline hierarchy would be to implement the logic automatically in the frontend, moving the control away from Storyblok, if you will. This way, you can make sure there is only one <h1> per page, followed by <h2> headings for sub-sections and so on.
This could be done by checking in the code whether the headline you are rendering is the first headline on the page - if it is, make sure it’s an <h1> , else, make it an <h2>. So first, we create our little helper function to check whether the element is the first one rendered on the page:
In the Page.svelte, we need to pass along the index in the <StoryblokComponent>
:
Then, in the individual components, we can import our helper function, pass in the index and by doing so, set the tag dynamically:
This automated approach gives you as a developer the most control over which headline level is set where. Of course, determining between <h1> and <h2> is only the tip of the iceberg, if you will. In a larger scale project, this set-up would have to be a little more complex, for example, by restricting what component can be used where and then for those components, which headlines can be used.
Conclusion
As you see, there are multiple solutions as to how you structure your headlines in a headless CMS - it’s a careful balance between the editors’ freedom to build their own pages and restrictions to avoid accessibility challenges and other pitfalls. As always, the best approach depends on your requirements but is definitely worth exploring.