jimmynotjim / scrollnav

A dependency free JavaScript plugin for auto generating single page navigation
http://scrollnav.com
MIT License
461 stars 127 forks source link

Accessibility: how to give focus to the selected heading #101

Open Spone opened 5 years ago

Spone commented 5 years ago

I think that for accessibility, specifically for people using the keyboard to navigate, it's a good idea to give focus to the h2 element that has been clicked.

I achieved that using the onScroll option:

scrollnav.init(content, {
  // ...
  onScroll: () => {
    const hash = window.location.hash;
    const heading = document.querySelector(hash);
    heading.focus();
  }
});

To make the h2 element accept focus, you also have to add tabindex="-1" to it.

(I'm posting this here if it can help others. Feel free to move it to the wiki or to the project documentation!)

Now I'm wondering what would be the best way to help the user go back to the "table of contents". If anyone has advice on the best way to do it, I would be happy to hear it!

jimmynotjim commented 5 years ago

Hey @Spone, glad to have more people thinking about accessibility, thanks for starting this discussion. I've thought a lot about this as well and there's a few issues with moving away from the default browser behavior I have yet to solve.

  1. If you move the user from the nav to the heading, how do you inform them of that change? What do we do about the text between the link and heading matching so it essentially repeats the text without a lot of context as to why.
  2. Headings aren't traditionally focused landmarks, so if the user tabs from the heading they'll jump to the next interactive landmark which might not even be within the content.
  3. Getting back to the nav is also a serious issue and I'm not sure there's any easily discoverable pattern we could include.

Have you seen any other examples out there that solve this while taking into account these concerns? Do you have any ideas on a solution that considers all of them? Keep in mind keyboard only users are already used to the current pattern. By default an ID link doesn't focus that ID, it only jumps the page, and tabbing after the page jumps takes you to the first item on the page, not the content after the ID.

Spone commented 5 years ago

Thanks for the feedback. I agree we need more feedback from keyboard-only users!

I have trouble finding recommendations about this particular design pattern. I read that but there are no details about implementation: https://www.nngroup.com/articles/in-page-links/

A quick sidenote (from the link above):

When users click an in-page link, the associated content should be scrolled close to the top of the screen, to make it easy for users to read as much as possible of the section.

With scrollnav, the content is scrolled until the heading reaches the middle of the screen. Any idea how to change that?

jimmynotjim commented 5 years ago

That scrolling to the ~2/3 window height is intentional. I created a "zone" that's active and if we scrolled all the way to the top the section could be outsize that zone. The reason I had to create a zone at all is because when the plugin just relied on whatever section was at the very top, it was possible for a section that was at the very end of the container to never be activated.

Spone commented 5 years ago

Yes I understand the reasoning, and I also think it's a good idea to have the active element near the middle of the screen instead of the top. It also prevent issues with fixed headers. But maybe it could be configurable? In my case I would prefer it to be in the first third of the screen.

jimmynotjim commented 5 years ago

It's definitely possible to make it configurable, I used to do that with the jQuery version but when I rewrote it for es6 in v3, I decided to reduce the configuration as much as possible because it was leading to bugs and extra maintenance. If you have some ideas on how to make it configurable without a ton of overhead I'm open to a PR.