Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How To Update URL Hash On Scroll (With Table Of Contents)

I found lots of answers on how to update a url hash when manually scrolled to, for example: <a href="#one">Topic 1</a>

However, what I really want is to update the hash when the user scrolls to, for example: <h2><a name="one"></a>Topic 1</h2>

I have a table of contents that allows the user to scroll to certain headings. But I also want to update the url hash automatically when the user scrolls to the H2 headings.

Here's a working example on of what I'm after on Healthline: https://www.healthline.com/health/baby/car-seat-expiration

Example HTML

Table Of Contents:
<a href="#one">Topic 1</a>
<a href="#two">Topic 2</a>

<h2><a name="one"></a>Topic 1</h2>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.

<h2><a name="two"></a>Topic 2</h2>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.

So basically, automatically update the url to include the hash when the user scrolls to each H2.

like image 764
Tnace Avatar asked Oct 27 '25 12:10

Tnace


1 Answers

Seemed like fun so I tried it out.

You have anchors with name attributes throughout your page, likely inside of a header tag; let's say an H1, but any would do.

Just takes a small bit of script to find all instances of this when you're scrolling and by using the history API and a bit of string magic you can overwrite the current location without causing the page to jump.

window.addEventListener('load', () => {
  const headings = document.querySelectorAll('h1 a[name]');
  
  document.addEventListener('scroll', (e) => {
    headings.forEach(ha => {
      const rect = ha.getBoundingClientRect();
      if(rect.top > 0 && rect.top < 150) {
        const location = window.location.toString().split('#')[0];
        history.replaceState(null, null, location + '#' + ha.name);
      }
    });
  });
});
like image 199
James Marks Avatar answered Oct 30 '25 02:10

James Marks