Navbar w/ Smooth Scrolling Same Page Links & Accessibility
Not as simple as it sounds…
There’s a few unexpected steps involved which left me scouring the internet for solutions. All the full solutions I found were bloated with ugly and long Javascript or using jQuery, etc which is really unnecessary.
Step 1 — HTML
1.1 — Create a Navbar
Here’s a simple example with links to sections on the same page with #id’s.
<nav class='navbar'>
<ul class='navbar__list'>
<li class='navbar__list__item><a href='#intro'>Intro</a></li>
<li class='navbar__list__item><a href='#meatnpotatoes'>Meat 'n' Potatoes</a></li>
<li class='navbar__list__item><a href='#stuff'>Stuff</a></li>
</ul>
</nav>
1.2 — Add Tab Index to html Sections
If you don’t set the tabindex you won’t be able to set focus when writing your Javascript (next step). By default, <section>’s are not focusable.
<section id='intro' tabindex='0'></section>
<section id='meatnpotatoes' tabindex='0'></section>
<section id='stuff' tabindex='0'></section>
Step 2 — Javascript
2.1 — Add Event Listener
In your Javascript file create an event listener for clicks on the navbar links.
- Select your links.
const navbarItems = document.querySelectorAll('.navbar__list__item');
- Loop over links & add listeners for clicks.
navbarItems.forEach(item => {
item.addEventListener('click', () => {
- Prevent the default behaviour.
Without this your links will jump instantly down the page ( :O no smooth, sexy scrolling! ).
event.preventDefault();
- Select section of page related to the navbar item.
let section = document.querySelector(item.childNodes[1].getAttribute('href'));
- Set scroll behaviour for section .
behaviour: ‘smooth’ will set it to smoothly scroll to the section.
block: ‘start’ will set it to scroll to the beginning of the section, rather than the center.
section.scrollIntoView({
behaviour: 'smooth',
block: 'start'
});
- Set webpage focus to the clicked section .
The scrolled-to section will receive focus, essential for accessibility & keyboard navigation.
setTimeout(() => section.focus(), 500);
Full code and if you want to see it in action I implemented it in my portfolio… not a shameless plug, I swear it just happens to be where I needed it!
const navbarItems = document.querySelectorAll('.navbar__list__item');navbarItems.forEach(item => {
item.addEventListener('click', () => {
event.preventDefault();
let section = document.querySelector(item.childNodes[1].getAttribute('href'));
section.scrollIntoView({
behaviour: 'smooth',
block: 'start'
});
setTimeout(() => section.focus(), 500);
}
}