This is some feedback from an accessibility audit for one of our forum instances. The story is specific to that forum (eg, the post titles) but it applies to Discourse overall. I left it in the author’s original words to get the flavor of the feedback
I started by clicking on the category "cookin on the job" since I like to eat!!
When you do this, the page does not refresh; it is modified on the fly. This is common practice now, however its drawback with respect to accessibility is that screen readers do not get a signal that content on the page has changed; the author is responsible to informing the user of this fact. The way this is done varies with the exact nature of what is being presented…
In this case, the two pieces of information the user must know are:
that something has actually happened (i.e. new information has indeed > appeared)
the nature of the new info (is this a message sequence, or merely another topic node)
If we click this category name, we indeed land on another topic node, listing the topics in this group (there is only one). So, the user would want to hear something like "1 topic found". This tells the user she has landed on a topic list, and how many items there are.
To implement this, place a div on the page (doesn’t matter where, but most likely at the end of the HTML), move it off-screen so sighted users will not see it, and mark it up as a live region, which tells the screen reader to speak all text changes within it without changing focus. FOr instance:
This seems like it might be complicated, but as an initial idea perhaps there’s an Ember routing hook that would let us do something global like “on route change, add in one of these screen reader-only tags to at least tell the screen reader that the data on the page changed.” That wouldn’t get at the need for “tell them what changed,” which seems more complicated and specific to individual features.
I’ve seen multiple articles mention that focus management is important.
Would code like this suffice for notifying the screen reader that navigation has completed?
// entered a topic
if (post_number === 1) {
ariaNotice("Entered topic"); // i18n of course
// inline title, not header title
document.getElementById('topic-title').focus();
} else {
ariaNotice("Entered at post {post_number} of {topic_title}"),
post_number, topic.get('title'));
// selects the <article> element
document.getElementById('post_' + post_number).focus();
}
note: focused elements needtabindex=-1 for JS-only focusing, or tabindex=0 for user focusing.
It may be worthwhile to change our J / K navigation to use .focus() instead of CSS classes.
So for the original issue on this thread, I think we could try @sam’s awesome suggestion to use the onPageChange hook. I can see how it works here, and the only question is where to enable that hook. I think we’d want to have this be enabled by default (with opt-out possible) and not a separate plugin.
If I’m reading through the code correctly, it looks like a new initializer in here would be the right place to add in that call to api.onPageChange. For now we could just have it do something like:
api.onPageChange((url, title) => {
Em.run.next(()=>{
// insert the .screen-reader-only div if it isn't on the page already
var screenReaderOnlyEl = document.getElementById('screen-reader-only-announcer');
if (!screenReaderOnlyEl) {
$('body').append('<div id="screen-reader-only-announcer" aria-live="polite"> </div>');
screenReaderOnlyEl = document.getElementById('screen-reader-only-announcer');
}
$(screenReaderOnlyEl).text('Page changed to: ' + title);
});
});