Hash Link Routing for React Applications
When working on a client web application earlier this year I needed to support a common navigation implementation. The users would need to be able to navigate directly to an element on a page using hash link routing.
My team and I were leveraging react router to handle our page navigation. After doing some research I reached for the most popular npm package I could find,
This package surfaces some components to be used as an alternative to
react-router-dom components such as
NavLink. The replacement components allow the user to navigate directly to elements on the page if the path specified in the value of the
to property includes a hash fragment and the target element has in
id identical to the hash fragment value. There is a stipulation that you must be using react router's
BrowserRouter to take advantage of this package which was fine with us because that's exactly what we were using.
However, for our use case, I quickly found that the flagship scroll-to-element functionality wasn't working as needed in the following circumstances:
- Browser forward/back operation to a URL with a hash fragment
- Opening a URL with a hash fragment in a new tab
- Page refresh
To my surprise this seemingly common problem was disappointingly not fully solved. Don't get me wrong,
react-router-hash-link is a completely valid solution for many use cases. Unfortunately, there were too many unsupported features for our use case.
At this point I had taken a look at a few popular packages in hopes that one would "just work". However, I ended up having to hand-roll the solution to fit our customer's needs. Using inspiration from
react-router-hash-link and this blog post I created
react-hash-link works in all of the following situations from the README.
- Navigating to a URL with a hash fragment and corresponding element on the page
- Opening qualifying URLs/pages in a new browser tab or window
- Forward browser navigation
- Backward browser navigation
- Page reload
- Works with
react-routerbut not dependent on it
- Works with server-side rendering
- All of the above scenarios function correctly when used across all major browsers (including IE)