Making the anchor links work in SPA applications

A solution for react-router and other history based routing #hash navigation

The problem is simple: when you link to a content in a single page application (SPA), the DOM changes happen after the URI history state changes. As a result, in the case of anchor links, browser does not scroll the target element into view.

There is an open react-router issue where multiple solutions to the issue have been proposed. However, the basic solutions fail in scenarios where the content is loaded asynchronously after the URI change.

The solution is simple:

  • use history to track when a new URI is pushed
  • use MutationObserver to track changes to the DOM tree after the URI has changed
  • use Element.scrollIntoView() to scroll the element into view when it becomes available
  • bail after a user-defined timeout or if new history action has been received

Here is a snippet that encapsulates this logic into a simple function, createHistoryHashObserver. This is a universal solution that works with any SPA.

Credit where credit is due

I have peaked into a solution provided by Rafael Pedicini in the aforementioned GitHub issue thread for inspiration. He even abstracted his solution in a package react-router-hash-link. However, I did not like that his solution forces to use a custom Link component and assumes defaults with no way to configure them.

If you prefer to abstract this at a React component level, I highly recommend react-router-hash-link .