DEV Community

Monica Mateiu
Monica Mateiu

Posted on

Improving Skip Navigation on DEV

As a career changer, DEV has played a big part in my development as a Software Engineer. The DEV Community Bug Smash seemed like the perfect opportunity to give something back to the community that helped me so much over the past two years.

My Open Source Background

My open source journey started with Hacktoberfest 2020 and with some small contributions to RubyForGood and upyoura11y. I wrote about that here. I found it very rewarding, and since then I've been trying to stay active and keep up the open source work.

But, to be honest, digging around in a large codebase like DEV's sounded pretty intimidating. So I took my time. I read through the open issues, looking for something that would speak to me. And then I found it.

About The Bug

Skip links are not the first focused element on internal navigation #13505

Describe the bug

Under #1153 we added skip links to all pages in the app. A skip link should be the first element focused on a page when the user presses the Tab key - however, this is only the case in a Forem if you land directly on a URL, and not if you navigate internally, e.g. by a link click.

There are several strategies available to managing focus on route change, but I would suggested the approach Marcy Sutton has written about following user testing with Fable: What we learned from user testing of accessible client-side routing techniques with Fable Tech Labs

The recommendation in that article is to send focus immediately to the skip link on the new page. We will need to experiment with :focus-visible to ensure that for users who navigated by mouse click, the skip link isn't visible. If this isn't possible, I think an acceptable fallback would be to focus an empty element directly before the skip link, so that once on the new page, the skip link is the first item focused on Tab press.

To Reproduce

  • Load the home page, and press Tab. You should see the skip link appear
  • Activate the skip link by clicking or pressing Enter
  • Select a post using the Tab key and press enter to view it
  • On the new page, press Tab again
  • Notice that the skip link is not the first item focused, and if you want to get to the main post content you have to press Tab multiple more times

Expected behavior

  • I select an article by keyboard on the home page
  • On the new page the skip link is visible and focused
  • If I repeat these actions but use the mouse, the skip link is not visible when I arrive on the new page

Navigation can be tricky in an SPA. The DEV team have done well to implement skip links across the website, but there was some work left to do: making sure that they display when the user navigates to a new link using a keyboard. @s_aitchison did an excellent job of describing the problem and the expected result in the GitHub issue, so all I had to do was follow her helpful instructions.

How I Smashed It

The team had already started a conversation around the issue and I wanted to make sure I fully understood the problem before I committed to smashing this bug. First I got the app running locally, then I took some time to explore it with a screen reader and reproduce the bug.

Once I understood what the expected behaviour should be and why, adding the code was easy. It took a few iterations, but the reviewers were very supportive, gave me lots of useful pointers, and helped me get around the mysterious behaviours of Safari. You can view the pull request below.

autofocus Skip Link on keyboard navigation #13828

What type of PR is this?

  • [ ] Refactor
  • [ ] Feature
  • [x] Bug Fix
  • [ ] Optimization
  • [ ] Documentation Update

Description

This PR aims to fix an issue where Skip Links only functioned when landing on a URL, not when using the keyboard to access internal links. With the added changes we are now sending focus immediately to the Skip Link when visitors are using a keyboard, and hiding it when a mouse is used.

QA Instructions, Screenshots, Recordings

Tested manually with keyboard and mouse on Edge, Chrome and Firefox. Ran checks using Axe DevTools and ANDI to ensure no unwanted behaviours have been introduced.

QA steps

  • go to the homepage
  • use the keyboard to navigate between pages and check that Skip Link appears on every link
  • use your mouse to navigate between pages and ensure that Skip Link does not appear
  • refresh the page and make sure Skip Link does not appear
  • press Tab and make sure Skip Link appears

Additional notes if you can't see the Skip Link in Firefox: On a Mac, making the Skip Link appear on Mozilla Firefox requires additional configuration. This post describes what you need to do, although there are a few missing steps. Follow the instructions on StackOverflow for setting up the keyboard behaviour on your Mac, then type about:config in Mozilla's URL bar. When you see the following message: Changing these preferences can impact Firefox performance or security, click 'Show all' at the top, type accessibility.tabfocus in the search bar, click the + icon to the right and update the number from 0 to 7, then click the tick icon on the right to save your changes. You should now be able to see the Skip Link on tab.

Demo https://user-images.githubusercontent.com/22390758/119253376-e53fde00-bba8-11eb-96e0-d17175d96ec0.mov

Added tests?

  • [ ] Yes
  • [x] No, and this is why: This PR only includes a CSS update and a small change to base.js.erb. I couldn't find any specs for this file, so I assumed the decision was to not test the behaviour defined here.
  • [ ] I need help with writing tests

[Forem core team only] How will this change be communicated?

Will this PR introduce a change that impacts Forem members or creators, the development process, or any of our internal teams? If so, please note how you will share this change with the people who need to know about it.

  • [ ] I've updated the Developer Docs and/or Admin Guide, or Storybook (for Crayons components)
  • [ ] I've updated the README or added inline documentation
  • [X] I will share this change in a Changelog or in a forem.dev post
  • [ ] I will share this change internally with the appropriate teams
  • [ ] I'm not sure how best to communicate this change and need help
  • [ ] This change does not need to be communicated, and this is why not: please replace this line with details on why this change doesn't need to be shared

Lessons Learned

Apart from the warm, fuzzy feeling that you've done something nice, the most valuable thing you'll get from open source contributions are the lessons you'll learn. Here's what smashing this bug taught me:

  • how to use CSS to adapt behaviour for both keyboard and mouse users
  • on a Mac, Safari and Firefox need tweaking to enable keyboard navigation properly
  • don't be afraid to work on new projects - poking around in a large codebase can be fun!

Discussion (17)

Collapse
inhuofficial profile image
InHuOfficial • Edited on

Great job, two things I noticed which may or may not be related to your work (they may always have been issues!)

  1. On the home page if you change the feed to Week, Month etc. the skip link is focused again. I am guessing it is because there is a URL change and that is where the focus hook is? A similar issue occurs on the notifications page if you switch between comments, posts etc, it jumps back to the skip link.

  2. Podcasts skip links do not work when on an actual podcast page. There are loads of errors in the console on that page so it might be nothing to do with the skip link itself.

If they are nothing to do with what you have done my apologies, I never checked the skip links until now and I do not want to detract from the improvements you have made! ❤🦄

Collapse
link2twenty profile image
Andrew Bone

There's a follow up about the same issue on search

"Skip to content" shows up erroneously on search submission #13876

Describe the bug

When I hit "return" on desktop to make a search on the platform, I see the keyboard nav "skip to content" element show up.

To Reproduce

  • Go to dev.to
  • Make search

Expected behavior

This element should not become visible.

Screenshots

Screen Shot 2021-05-28 at 10 35 26 AM

Desktop (please complete the following information):

  • OS, version: MacOS 11.2.2
  • Browser, version: Chrome 90.0.4430.212

I think it's possibly expected behaviour for changing tabs as it does reset keyboard focus.

As for the podcast page I think the page itself needs looking at, I can't see a way to start a podcast without the mouse. I don't think it's related to this PR though.

Collapse
inhuofficial profile image
InHuOfficial

Changing tabs shouldn't reset focus as it is all done via AJAX, instead you should either use aria-live and say "loaded" when complete or focus the first item in the list (SPA pattern).

That issue you quoted is a tough one with the current pattern. I would suggest on that page that nothing is focused initially and the first Tab press is used to activate the skip links as there is no real way of differentiating keyboard and mouse users.

To be fair the whole pattern is a little unusual, I like it, but normally on navigation you would expect nothing to be focused on a page change and the first tab to show the skip link.

On a SPA application you would expect the <h1> of the page to be focused once loading is complete.

As Dev.to is a hybrid I think the solution implemented is a nice balance and the work done on this is great, just some minor points which may be there own issues.

Thread Thread
link2twenty profile image
Andrew Bone

The pattern was taken from this blog post.

Thread Thread
inhuofficial profile image
InHuOfficial • Edited on

I will have a proper read but I dont see an aria-live region in the elements tab in dev tools to indicate the current page?

From a skim read that looks to be the pattern they settled on?

SKip link focused, aria-live to notify of current page?

I might be missing it though as I am not on my main PC and it is hard to assess from here.

The advice now looks like this:

  • Provide a skip link that takes focus on a route change within the site, with a label that indicates what the link will do when activated: e.g. "skip to main navigation".
  • Include an ARIA Live Region on page load. On a route change, append text to it indicating the current page, e.g. "Portfolio page".

Under "Recommendations: finding common ground"

Thread Thread
s_aitchison profile image
Suzanne Aitchison

Changing tabs shouldn't reset focus as it is all done via AJAX, instead you should either use aria-live and say "loaded" when complete or focus the first item in the list (SPA pattern).

The tabs on the home feed aren't true "tabs" in the usual sense of toggling a small section of page visibility - they're actually links within a nav and clicking on them results in a fresh page load, which is why a user would need a skip link to get them back to the main content with ease.

Podcasts skip links do not work when on an actual podcast page

Looks like a page was missed when implementing the skip links! We'll get a quick fix up for that ASAP - nice spot 🙌

Thread Thread
inhuofficial profile image
InHuOfficial

Ah I see, because of the prefetching making it load instantly I thought it was an AJAX call, my bad! I should have checked the network tab before opening my mouth 😂😋

Thread Thread
s_aitchison profile image
Suzanne Aitchison

I will have a proper read but I dont see an aria-live region in the elements tab in dev tools to indicate the current page?

You're right! It's not related to @metamoni 's PR, but actually I missed this when implementing the skip links originally - we'll get this fixed 😄 But yes, that's the pattern we've been incrementally adopting, based on the research presented.

Thread Thread
inhuofficial profile image
InHuOfficial • Edited on

It is a really interesting pattern I haven't seen before so I look forward to seeing it in full form.

I think the aria-live region is the way they decided to address the problem I raised (I still haven't had chance to test, just my gut reaction from experience) in that if you manage focus it will interrupt reading the page title etc.

I hope the pattern works well as I do actually prefer the keyboard interaction this way (1 extra tab stop removed is always welcomed!) and once you have all had the headaches of implementing it I can learn from out of the way I might just be stealing it 😋🤣.

Thanks for the super quick responses @s_aitchison !

Sorry @metamoni didn't mean to hijack this as the work you have done is great!

Thread Thread
inhuofficial profile image
InHuOfficial • Edited on

I would imagine the fix for this would be super simple for a quick fix while a more flexible solution is created:

Add an aria-live region to all pages for site announcements. ID = "ariaLiveDiv";

// page load complete stuff before here

let announcerDiv = document.querySelector("#ariaLiveDiv");

announcerDiv.innerHTML = document.title;

//the focus step after page load
mySkipLink.focus();

Enter fullscreen mode Exit fullscreen mode

It would stop gap the issue while you set more meaningful text for each page (as the titles aren't always the best for things like comments etc but work great for the core part of the site such as articles, reading list, home etc.)

Thread Thread
metamoni profile image
Monica Mateiu Author

Wow, some interesting discussions here while I was at work. Thank you, @inhuofficial and @s_aitchison , I'm learning a lot from all of this 😄

Collapse
inhuofficial profile image
InHuOfficial

I just had a thought that I am hoping I am wrong about.

I haven't fired a screen reader up (will do that later when on main PC) but I have just had a horrible thought...if the link is focused on page navigation does it interrupt reading the page title etc. If so this whole pattern would make accessibility much worse for screen reader users as every page you land on would just be called "skip link" as far as they are concerned and they would have to use other controls to ensure they are on the right page.

Thread Thread
metamoni profile image
Monica Mateiu Author

There is an h1 on every page. This is the first item read out by screen readers after you hit Enter on the skip link.

Thread Thread
inhuofficial profile image
InHuOfficial • Edited on

Sorry, I think I need to explain this point further as I think I made it confusing mixing the two patterns together.

When you manage focus on a page load (adding focus to the skip link or focusing a <h1> etc.) it will interfere with a screen reader normal announcement, which would be to read the page title etc.

On a true SPA application (content loaded via AJAX - header and footer remain rendered) focusing the <h1> is the preferable action as there is no page refresh so the page <title> will not be read out. This helps screen reader users both know where they are and also know the page has loaded. (This is assuming the <h1> for the page is descriptive.)

However in dev.to I was incorrect as the page does actually reload so it isn't a SPA pattern and we can ignore that bit (I goofed!!).

In this case the page loads like a normal site, even for the home page feed tabs etc.

So we fall back to a normal pattern. A screen reader would start to read the page title but we interrupt it with focus management focusing the skip link. This makes navigation via a screen reader more difficult as you cannot confirm you have landed on the correct page via the title being read out automatically.

This is why we were having a discussion about adding the page <title> content to an aria-live region on the page. That way we can still use your skip link focus, but a screen reader user will also hear the current page title and know where they are.

Now they could just press Enter to get to the <h1> and hear what page they are on (except for podcasts page as that appears to be a <h4>?) But at that point they have skipped navigation...so they would have to go back to the navigation if they had made a mistake.

It wouldn't take long to get used to the pattern, it is just not expected behaviour (and expected behaviour is one of the core things to look at on accessibility for screen readers to make discovering a new site easier).

It isn't a huge issue, it has just inadvertently made the experience a bit worse for screen reader users while you improved the keyboard usability greatly for others. The joys of accessibility is that stuff like this happens all the time! 🤣

I hope that makes more sense, but if not let me know! Honestly I should have just done a jsfiddle or codepen as the concept is really simple...it is my terrible explanations making things difficult! 🤣🤣

Collapse
nickytonline profile image
Nick Taylor • Edited on

Congrats on your first contribution to Forem!

You did it!

Collapse
ryankilleen profile image
Ryan Killeen

I remember seeing the more mature issue linked to my pre-forem, proto-issue and I was so happy to see someone tackling it! Well done!

Collapse
link2twenty profile image
Andrew Bone

Well done sloth