skip to content

JavaScript: Replacing anchor links with JavaScript

Anchors in HTML are essentially bookmarks within a page that can be targeted directly by adding an anchor reference starting with '#' to the URL. The browser will then jump to the specified anchor.

However when a link targets an anchor on the same page the browser 'Back' button will no longer take the browser back to the previous page, but to the previous anchor.

What is an anchor

There are two ways of marking anchor points on the page. The old method is to use the <a> tag with a name attribute. It's a bit awkward as you can see:

<h2><a name="some-heading"></a>Some Heading</h2> <h2><a name="another-heading">Another Heading</a></h2>

The more recent technique is to assign an id where you want the anchor:

<h2 id="some-heading">Some Heading</h2>

In either case we can send the browser to that section of the page by appending the anchor to the URL using a hash (#):

http://www.example.com/some-page.html#some-heading

For linking to an anchor on the same page we use:

<a href="#some-heading">Click here to jump to Some Heading</a> <a href="#another-heading">Click here to jump to Another Heading</a>

An id value must be unique on the page and start with a letter. It can then contain numbers, dashes and underscores. Colons and periods are also permissable, but can cause problems with certain JavaScript libraries.

Jumping to anchors with JavaScript

While less common now there is a simple technique for jumping to anchor points using a SELECT input for navigation. It requires just a touch of JavaScript:

<form method="GET" action="#" onsubmit="return false;"> <select onchange="self.location.href = '#' + options[selectedIndex].value;"> <option>-- jump navigation --</option> <option value="some-heading">Some Heading</option> <option value="another-heading">Another Heading</option> </select> </form>

The result, which can be nicely styled using CSS, is the following:

You will see that when an option is selected the browser jumps to a new anchor point on the page and the anchor (#) appears in the URL.

A pure JavaScript solution

In all the above examples the browser is taken to different parts of the page my modifiying the URL, and this makes the 'Back' button behaviour less intuitive.

What if we could keep the benefits of using anchor points, but remove the drawback of polluting the browser history?

The solution is to use the scrollIntoView method which is supported in all major browsers. It scrolls to the (any) selected element without changing the URL.

document.getElementById("some-heading").scrollIntoView(true);

We still need to mark the anchor points using an id, but now the browser history remains unaffected.

Applying this to the SELECT navigation we end up with:

<form method="GET" action="#" onsubmit="return false;"> <select onchange="document.getElementById(options[selectedIndex].value).scrollIntoView(true);"> <option>-- jump navigation --</option> <option value="some-heading">Some Heading</option> <option value="another-heading">Another Heading</option> </select> </form>

The behaviour is the same, only that the browser URL stays the same.

Applying a polyfill

The following code will parse your HTML page and override the function of any links that target anchor points on the same page. The link function will be replaced with a call to the scrollIntoView method of the target element:

<script> window.addEventListener("DOMContentLoaded", function(e) { // Original JavaScript code by Chirp Internet: www.chirpinternet.eu // Please acknowledge use of this code by including this header. var links = document.getElementsByTagName("A"); for(let i=0; i < links.length; i++) { if(!links[i].hash) { continue; } if(links[i].origin + links[i].pathname != self.location.href) { continue; } (function(anchorPoint) { links[i].addEventListener("click", function(e) { anchorPoint.scrollIntoView(true); e.preventDefault(); }, false); })(document.getElementById(links[i].hash.replace(/#/, ""))); } }, false); </script>

On page load the function loops through all links (<A>) on the page looking for those that have a hash in the target address AND that point to the current page (self.location.href).

We add an onclick event that overrides the default browser behaviour. The script assumes that all anchor points have been marked up using the id technique.

You can see the effect on these two links. They are marked up as normal links, but when the page loads our script 'upgrades' them:

Unlike before, you can trigger these links as often as you want, but the Back button will still go to the previous page and not the previous anchor point you've visited.

Extra code will be required to support IE8, as usual, and you might want to check that the target id actually exists before assigning the new handler to a link.

Using querySelectorAll

For modern browsers we can clean up the code a bit by switching to querySelectorAll for identifying links on the page:

<script> document.querySelectorAll("a[href*='#']").forEach(function(current) { // Original JavaScript code by Chirp Internet: www.chirpinternet.eu // Please acknowledge use of this code by including this header. if(current.origin + current.pathname != self.location.href) { return; } (function(anchorPoint) { if(anchorPoint) { current.addEventListener("click", function(e) { anchorPoint.scrollIntoView({behavior: "smooth"}); e.preventDefault(); }, false); } })(document.querySelector(current.hash)); }); </script>

This gives us the flexibility to restrict the function to a certain section of the page:

document.querySelectorAll("#contentdiv a").forEach(...);

or to links with a specific class:

document.querySelectorAll("a.scrollto").forEach(...);

At the same time, we've set the behaviour of the scroll transition to 'smooth' which results in a smooth transition in supported browsers (all except for Internet Explorer and Safari). For more options, check out the links below.

References

< JavaScript

User Comments

Post your comment or question

24 September, 2020

You're a lifesaver! I was able to completely ditch the whole 'navbar thing', by implementing your solution. The real bonus is that moving to and from page sections is super fast and intuitive and I now have a website that works as I have intended it - just like an app. A big THANK YOU!! You've just made my day (*•̀ᴗ•́*)و ̑̑

29 August, 2019

For SPAs, I've been using the tried-n-true anchor JS onclick() listener pattern to hide/show "<section>" in my document. While you're suggestion is very cool, not sure I'm ready to switch over just yet.

17 June, 2019

Thank you so much for your help, I needed to know about url redirect with anchor tag and this javascript function did the trick:

$(function(){
document.getElementById("content").scrollIntoView(true);
});

And I descovered that I have used it before but for different reason.
BR.

14 March, 2019

Very Cool! I'm using that script on some projects of mine, and it works perfectly!

20 April, 2016

Hi. will this work within html email as an anchor alternative. Especially with the iOS8 and above..?

top