11ty-website
11ty-website copied to clipboard
Skip link for docs (accessibility improvement)
Is your feature request related to a problem? Please describe. Let's suppose you use a keyboard to navigate through Eleventy docs main page. In order to focus some element within main content (such as link) you have to tab through whole navigation on the left. It takes a while, because there are 57 links in the sidebar!
Describe the solution you'd like Skip link. If you use tab key on the site, you'll be asked to:
- skip to main content
- skip to sidebar navigation
Skip link will show up only if tab key used.
Describe alternatives you've considered I have not considered any alternatives ;)
Additional context See how Google does it:
@zachleat if you like the idea, I'll be happy to contribute :)
Yes, this is very much needed! Moving this to 11ty-website repo.
Great. I already started to code. Do you think the way the buttons look is fine or do you prefer something in different style?
Looks great!
@zachleat I'm having trouble with choosing the best element to focus on while clicking "skip to main content". Initially, I thought it would be a good idea to focus on whole content section. However, if I wrap content within some div
which has tabindex="0"
then if someone clicks anywhere within text's body, whole section will focus. It's not natural I'd say - outline around text looks weird.
I realized that each page has title that I can set focus on. But I cannot find where markup for this title (highlighted element) is made? I would like to add tabindex="0"
to every heading so I can set focus on it.
So you shouldn't need to set tabindex=0 for skip links, instead the recommendation is to set tabindex=-1. This still allows the focus to be moved without causing the problem you discovered. An even better solution is to set and remove the tabindex as the links are interacted with. Here's a solid article that talks about how skiplinks are often broken: https://axesslab.com/skip-links/
The last solution seems to be the most recommended one. Though it does require some JS to get it fully working.
Here's the approach that I'd recommend:
- add an id="main-content" and tabindex=-1 to main.
- remove the tabindex after the document loads. This lets the skip link work with JS disabled, but isn't a perfect experience.
document.onload = () => { const main = document.getElementById('main-content') main.removeAttribute('tabindex'); }
- Define a function to handle link changes. The example in the above article binds to the window and then performs an action on blur + focus. So in vanilla JS, that would look something like this:
function focusOnElement(el) { // set a tabindex = -1 so element can be focused element.setAttribute(tabindex, -1) element.addEventListener('blur', () => {element.removeAttribute('tabindex')}, {once: true}) element.addEventListener('focusout', () => {element.removeAttribute('tabindex'), {once: true} } //setEventListener to remove tabindex after focusout element.focus() } window.onhashchange = () => { const targetElement = document.getElementById(window.location.hash.replace(/#/, '')) // removes the hash from the id if(targetElement) { focusOnElement(targetElement) } }
So based on some more recent testing. The iOS bug referenced in the article above is no longer valid. But, in the name of progressive enhancement (older iPhones, and anyone using older versions of Chrome or Internet Explorer), I'd still recommend a similar approach to above.
This means that while you still need an id on main, you no longer need the tabindex=-1 initially. This also means you can skip step 2 entirely. There's an added bonus that this will improve the experience for mouse users who may have JS disabled while visiting the docs.