The structure of a page rendered to the browser is important. If you already understand this, and why, then ignore this next part, it’s not for you. Maybe you don’t think it’s important because you’ve been putting everything into divs and spans and HEY THAT’S WORKED OUT OKAY MEL. If by “okay” you mean “it builds” then technically you’re correct, given that limited definition, but it’s still not okay. HTML is implicitly error-tolerant, which means it’ll still work no matter what you do to it. That level of error tolerance doesn’t mean HTML is less important, it means it’s different important- and quite frankly, to consider it as less important makes you a jackass, even if I can empathize with why you might think that way.
HTML markup isn’t meant to make it work in the same way our JS files make it work. HTML is meant to give the content semantic meaning. This matters to assistive technology. Assistive technology (AT), like a screen reader or browser plugin(!), uses landmarks to programmatically identify sections of a page. It gives users a way to choose how to navigate the content of the page.
If you’re still struggling with coming to terms with why/how this matters, here’s one way to think about it: You like having options, right? You like the ability to choose things. How would you feel if that was taken away from you? How would it feel if you knew others could choose, but you were prevented from choosing? Think about that for a little bit.
Okay, now that we’ve gotten that out of the way, let’s talk about landmarks so we can understand how to use them. Here are a few tips:
- The landmarks indicate the primary content items on the page.
- All content should be in a landmark (to make an over-simplified analogy: all children need parents. I know. It’s not perfect. Feel free to come up with your own.)
- Landmarks can be nested (It makes your life easier if you avoid this until you understand it better).
- Landmarks should be labeled (aria-label or aria-labelledby).
- Don’t use the landmark role in the landmark label, because AT already reads out the role after it reads out the label.
There are 8 landmark roles:
Banner & Contentinfo
- TL;DR: put role=”banner” on the header, and role=”contentinfo” on the footer. Use them just once.
- If in the context of the <body> element, if you use the <header> element then you don’t need the role=”banner”. Same goes for <footer> and role=”contentinfo”. BUT if you’ve nested these in sectioning elements, they will not have this default role.
- Level up: Since you can nest document/application elements, you could theoretically have more than one banner & contentinfo. But don’t try this at home until you have fully embraced semantic HTML and really know how it works.
- This is used for “a supporting section of the document” that is at the same DOM level as the main content, but is still meaningful when you separate it from everything else.
- The content that goes in the element marked complementary should still be related; if it’s not, then use a different role.
- If it’s an <aside> element, you don’t have to put role=”complementary”.
Form & Search
- For the <form> element (shocking, I know)
- If the form is not a search, use role=”form”; if the form IS for a search, use role=”search”.
- The form should have a visible label, which can be indicated through the use of aria-labelledby, like this:
- Did you see that I didn’t include role=”form”? That’s because it has a label.
- Here’s how you’d do a search:
- “But there’s no visible label!” Au contraire, mon ami. The button says search and is the visible label in this context. YAY!
- On a form, you could also use the title attribute. I don’t recommend it because this tends to be not consistent on mobile devices. Because Android and stuff.
- Now, as you already know, Ember provides an ID (https://emberjs.com/api/classes/Ember.ViewMixin.html#property_elementId). This means you could do all of this in your component code via attributeBindings (https://emberjs.com/api/classes/Ember.ViewMixin.html#property_attributeBindings) and then not think about it anymore. Which I think makes it sooooo much easier.
- The main content of a document or application.
- If you use the <main> element, you don’t have to put role=”main”.
- Have one of these. Yes, the documentation says you can nest and therefore have more and….yeah, but no. If The Reasons Why™ apply to you, then just have one. We picked Ember because we’re building really complex stuff in the first place, and this is an easy win to make your architecture more meaningful and this is one area where you don’t need the added complexity, nor will I really give in to any excuses. I’ve never seen a legit use case for using more than one of these.
- If you use the <nav> element, you don’t need to add role=”navigation”
- if you have more than one <nav> element on your page, then it needs to have a unique label.
- if you have two navigation elements on your page that have the same content (but why tho?) then they should have the same label.
- This word does not mean what you think it means.
- I’m going to do a whole post just on how to use this and not lose your mind. So I’m not going to go into it here.
Bonus Role: Region!
- The role=”region” is the catch-all for “something that really should be in its own landmark but the other ones don’t really fit it.
- If you find yourself using this too much, rethink the design.
This part is pretty cool, you should try it yourself. Especially if you like to be super pro keyboard user, you can be zipping around pages in no time. I’m only going to cover a couple, so you might have to look it up if you use something different.
- There are some browser extensions that will allow you to navigate landmark regions on a page. Explore.
- NVDA + Firefox (Windows):
- D will go to the next landmark
- SHIFT + D will go to the previous landmark
- NVDA + F7
- VoiceOver on iOS
- W will go to the next landmark
- SHIFT + W will go to the previous landmark
- CTRL + OPTION + U will give you a list of landmarks (that you can keyboard navigate through/to)
Okay, that’s it for now. Hopefully this guide has given you a clear path forward for using landmark roles and helped you see ways that HTML5 & Ember already help you do this.
Up Next: Application vs Document Roles