Skip to main content
@spa-tools/core-router

Hash Autoscroll

Using URL hashes to scroll to content has been around a long time, but this native functionality can get ugly and convoluted when implemented in a SPA, especially when you're trying to scroll to a specific element right after a view loads.

While the @spa-tools/core-router typically stays out of the UI rendering/interaction business, this is one scenario it dives head first into to enable simple auto-scroll to html elements via its navigation feature.

import { CoreRouter, routesFactory } from '@spa-tools/core-router';

const createMyRoutes = routesFactory();

// here we create two routes where we will "pretend" that the About
// route has a "Careers" section that we want to auto-scroll to
const myRoutes = createMyRoutes({
homeRoute: {
path: '/',
},
aboutRoute: {
path: '/about',
// here we specify that for this route we'd like any auto-scrolling
// via hash navigation to be smooth; we could omit this and the
// behavior would default to 'auto' or we could also set it to 'instant'
hashScrollBehavior: 'smooth',
},
});

// here we create a new instance of the CoreRouter class and pass in
// our routes object; we also pass in an object that implements the
// router lifecycle callback onRouteChange so we can log outcomes
const myRouter = CoreRouter.initialize(myRoutes, {
onRouteChange: (routeChange) => {
// this is where we would perform any post-processing logic, which
// typically means rendering the requested route. How to do this
// ranges based on the UI framework being used, so here we simply
// log path info to the console.
//
// If you're using React or want to create an abstraction for a
// different rendering package/framework, you should definitely
// check out the Core React Router abstraction, which has the
// rendering logic sweetly baked in.
console.log(
`Route change with hash in path: ${window.location.pathname + window.location.search + window.location.hash}`
);
},
});

// first, we navigate to the home route
myRouter.navigate(myRoutes.homeRoute);

// next, we navigate to the about route and specify a hash so the
// browser will auto-scroll to the Careers section, if it exists.
// And by exists, we mean that the rendered content must have a
// DOM element with the ID of "careers".
//
// And that's it. Easy-peasy. Pretty cool, huh?!?!
myRouter.navigate(myRoutes.aboutRoute, undefined, 'careers');