ARIA compliant filter search
I've managed to find some time to spend at my computer recently, after all the festivities and flu. I decided I would continue working on the accessibility and ARIA compliance on my main website. Next on the list was the filter search that I use on my index pages.
Each article has a list of tags (which I call topics on my site), and some JavaScript code makes a list of clickable topics near the start of the page that will filter the articles that contain the selected topic.
The first thing I decided to do was to place the all the filter search related elements into a search element. I hadn't known this element existed until I researched ARIA. So now it's all in a semantically named landmark for assistive technologies to distinguish. Great!
In the dev tools in Firefox, I was getting a warning in the accessibility pane that these things that behave as buttons do not have the role of buttons. Originally it was because I had the CSS made up for my topic tags, so I just made the same topic tags to sit at the top of the page - the only difference being that these ones are clickable. Well, if something behaves like a button, why not just make it a button? I've styled my buttons in my website to look like anchors, but with descriptive text that makes it quite obvious that this thing I click does something on the page instead of taking me to a different page - it's fine, it's visually noticeable and the intent is explicitly indicated. So I had to do some CSS trickery to make these buttons look like topic tags instead. Everything looks the same as before, except now the topic buttons are now focusable, and there's a sensibly named landmark.
One more thing about buttons: as these are stateful buttons, I also needed to include the aria-pressed attribute.
Previously (or currently, depending on when you're reading this; I still have to make some updates to the CMS Python module to reflect these changes), I have truncated the topics list using max-height and a fade with overflow: hidden. I set a resize listener on the window to pick up on when a browser window might be tiled to the side - I was truncating the list if it exceeded X amount of the vertical screen real estate. When I gave it some thought, I realised there were 2 issues with this. The first is that although they are hidden from view, all the topics were still in the accessibility tree, so for my guides index page, a user would have to sit through 37 topics before getting to the article links. That's too many. The second was my realisation that this is what was responsible for a graphical glitch on only some mobile browsers - particularly the browsers that hide the address bar on scroll, and you know, resize the window? Duh. How did it take until now to realise why that was happening? (face-palm).
So threw away my JavaScript truncation, and replaced it with a fairly tidy piece of CSS:
search#topics {
...
&.truncated li:nth-of-type(n+7) {
display: none;
}
}
Now, when the truncated class is applied to the ul element, only the first 6 topics are rendered. Thanks to display: none;, this is the case for the visual document and the accessibility tree.
Next I needed some user messages, with aria-describedby, aria-live="polite", and role="status" to indicate the various states of the topic list. There are two different "statenesses" here, if you will pardon my English.
- If a filter is currently applied or not
- If the list of topics is truncated or not
I'm not sure that two status indicators can describe the same UI component, and I didn't want to potentially create confusion even if they could. So I bundled both messages into the same p element, with a span for each and an id to distinguish between each. With the user feedback messages, all the lines I had stripped from my JavaScript file were quickly refilled with new code. But for a better experience for an end user: it's arguably worth it.
Any structural work to my website, such as this, requires some modification and testing with the CMS module. But after that's done and changes are pushed, I shouldn't have to think about it again. There is one aspect I'm mulling over before I finalise my changes: when all filters are showing, i.e. no truncation, and a topic is selected to apply a filter that is placed after where the truncation would occur (so index 7 onwards), if the topic list is then truncated, then that topic is hidden and can't be deselected without reopening the full list. It's a dead end situation that can be escaped, but requires more analysis and problem solving than what is fair to place onto an end user. As I assess, I think I may be able to just apply display: inline; to the selected topic to override the display: none; that is applied to truncate it, ensuring any selected topic is not hidden from view, regardless of it's index.
When looking up potential methods for applying a search filter, I came across a few different options that I didn't really vibe with for this use case. But I must admit I was especially pleased that W3 schools offered the same solution as I has already came up with myself. It's nice to have some affirmation that you are making good decisions.