Semantic HTML and ARIA explained

Originally published on CSS-Tricks.

Semantic HTML and ARIA (Accessible Rich Internet Applications) help create interfaces that work for everyone in the most performant, robust, and simple way possible.

They add essential meaning to your content, which lets web browsers, search engines, screen readers, RSS readers, and ultimately users understand it.

And yet many people still don’t use them. I wanted to know why that was, so I set up a Twitter poll. The most common reason people gave was a lack of awareness and understanding.

So here I’ll describe the benefits of using them, and explain why you should start with semantic HTML, and only use ARIA as a last resort.

Starting with raw text

The <body> element of an HTML document contains the main content a user sees on a page. If content is put inside the body without any additional elements, the browser has no way of differentiating between different types of content, like paragraphs and headings.

I’m the page heading.
I’m a paragraph.
I’m a sub-heading.

If the browser can’t differentiate between pieces of content, then it can’t present that content to the user in a meaningful way. That means:

  • you can’t use CSS to style the headings differently from paragraphs
  • search engines can’t index the content, meaning it will rank poorly and users will struggle to find it
  • screen readers and other assistive technology can’t communicate it properly to the user

Adding some structure with HTML

To provide some structure you can wrap your content in <div>s like this:

<div>I’m the page heading.</div>
<div>I’m a paragraph.</div>
<div>I’m a sub-heading.</div>

This is better because instead of one big block of text, each piece of content is displayed in the browser on its own line. But there’s still a distinct lack of meaning.

That’s because the headings and paragraph are wrapped in <div>s which are meaningless on their own. In this example, browsers, CSS, search engines and screen readers are still none the wiser.

Styling content

You can add visual styling to different elements using CSS:

div:first-child { /* styles here */ }
div:nth-child(3) { /* styles here */ }

Here the CSS targets the first and third <div>s to apply heading styles. This isn't maintainable because another paragraph added afterward, for example, would get styled as a heading.

You could give each <div> a unique attribute such as an ID or class name, to provide more control:

<div class="heading1">A Study of Butterflies</div>
<div class="paragraph">Butterflies are little bugs with cute wings.</div>
<div class="heading2">Butterfly Habitats</div>

(Note: I explain why you should use classes instead of IDs for styling in my online book, MaintainableCSS.)

You can now target the different elements with CSS like this:

.heading1 { /* styles here */ }
.paragraph { /* styles here */ }
.heading2 { /* styles here */ }

This will make the paragraphs and headings look different, which works for sighted people who use a browser. But it doesn’t provide meaning to search engines, RSS readers and screen readers. In other words, it’s not semantic and it’s not very accessible.

Giving content meaning

HTML provides many elements that give meaning to content, including elements for headings and paragraphs.

So instead of <div>s with class attributes made up by the author (me in this case), you can use predefined HTML elements which are built specifically for this purpose.

<h1>I’m a heading</h1>
<p>I’m a paragraph</p>
<h2>I’m a sub-heading</h2>

With semantic HTML like this, your content will get some default styles from the browser. You can add other elements like <b> which means “bring to attention” to make text bold.

Crucially, using semantic HTML also means:

  • you can use CSS to add your own styling
  • search engines can index the content so that it ranks well enough that users can find it
  • RSS readers can style the elements appropriately
  • screen readers and other assistive technologies can communicate it properly to the user

The code is also more concise which, while not massively important in these short examples, makes a big difference when considering an entire site.

Semantic HTML is standards-based and stable. This means any HTML processor in the future will be able to understand it and present it correctly to users. It will also help other code authors to understand it if they’re editing the code in the future.

Additional benefits of semantic HTML

As well as the benefits I’ve described, some browsers add useful enhancements to semantic HTML for free.

For example, using the HTML telephone input (<input type=”tel”>) will give users a telephone-specific keypad on some mobile browsers.

Other browsers give users the option to switch on a simplified view of the page, like Safari’s Reader Mode. Without semantic HTML, this functionality won’t work.

You can read more about this in Mandy Michael’s article on building websites for Safari Reader Mode and other reading apps.

Using ARIA

Like semantic HTML, ARIA is a W3 standard that helps you make interfaces more accessible to users of screen readers and other assistive technologies.

A good example is error messages. If a user leaves a required form field blank, the HTML for the error might look like this:

<label for=”first-name”>First name</label>
<input type=”text” name=”first-name” id=”first-name”>
<span>Enter your first name</span>

A sighted user will be able to see the error underneath the field. But when a screen reader focuses the input, the error won’t be announced, because the error message isn’t linked to the input.

You can use ARIA to associate the error with the input like this:

<label for=“first-name”>First name</label>
<input type=“text” name=“first-name” id=“first-name” aria-describedby=“first-name-error”>
<span id=“first-name-error”>Enter your first name</span>

ARIA and JavaScript

ARIA is most useful when JavaScript is involved. JavaScript is usually required to create more complex and dynamic interactions like hiding, showing and changing elements without a page refresh.

Think toggle menus, accordions, tabs, autocompletes, sortable tables, loading content and saving, sending or getting data. Enhancing interfaces like this often breaks the experience for screen reader users.

Take a button that, when selected, shows some other content. In the original state, a sighted user can see a button and no content showing. When they select the button, the content appears.

However, visually-impaired people who use screen readers are usually relying on things being announced as they move through an interface.

But when a screen reader user focuses the button, there’s nothing by default to tell them if the content is currently being shown or not.

You can add the aria-expanded attribute onto the button, and toggle it’s value between true (content is showing) and false (content is hidden). This helps to provide a comparable experience (inclusive design principle 1) to screen reader users.

<button aria-expanded=”false”>Toggle content</button>
<div hidden>Some content</div>

Avoid using ARIA to fix unsemantic HTML

ARIA attributes can be used to make unsemantic HTML more accessible to screen reader users. For example, a developer who is struggling to style a native checkbox across multiple browsers might decide to use a <div> and some JavaScript to emulate one.

To make the <div> identify itself as a checkbox to screen reader users, we can give it a role of checkbox like this:

<div role="checkbox"></div>

To indicate whether or not the checkbox is checked, we can use the aria-checked attribute like this:

<div role="checkbox" aria-checked="false"></div>

But, this still isn’t enough to make it behave like a checkbox because divs aren’t focusable by keyboards like <input type="checkbox"> is. You can make them focusable by adding tabindex="0":

<div role="checkbox" aria-checked="false" tabindex="0"></div>

But even then, a real checkbox, when submitted as part of a form, will send its value. Because this isn’t an actual a checkbox, it won’t submit its value without using JavaScript.

And if that weren’t enough already, users can check or un-check a real checkbox by pressing the Space key. And, the form the checkbox belongs to can be submitted by pressing Enter when the checkbox is in focus. But the <div> checkbox won’t do this without even more JavaScript.

Not only is this more work and more code, but the approach only actually works for people who use technology that understands these particular ARIA attributes.

That’s a lot of effort, a lot of code and a lot of problems that we can avoid entirely if we just use semantic HTML:

<input type="checkbox">

There’s no denying that ARIA is useful in certain situations, but starting with semantic, accessible HTML where possible is infinitely simpler and more reliable.

That’s why the first rule of ARIA is not to use it.

In conclusion

Inclusive design is about providing the best possible experience to the broadest range of users.

Semantic HTML helps technologies and therefore users understand your content. Enhancements offered by some browsers and devices mean your users get an even better experience baked in.

When semantic HTML alone is not enough, ARIA can provide more information for users of assistive technologies–but use it with caution. It’s not a sticking plaster for inaccessible code.

In short, do the hard work to make things inclusive.