Photo by Joan Gamell on Unsplash
Creating Sectional-Based Routing in a SPA with Smooth Scroll Navigation
Table of contents
Building a Single Page Application (SPA) often involves creating smooth and user-friendly navigation. One common challenge is ensuring that navigation links scroll smoothly to the appropriate section of the landing page, even when the user is currently on a different route. In this post, I'll show you how to implement sectional-based routing with smooth scrolling using React and React Router, enhanced by a simple custom function to handle scrolling and navigation.
Problem Statement
While using libraries like react-scroll can facilitate smooth scrolling within a single page, issues arise when navigating from a different route back to the landing page. Specifically, clicking a navigation link to scroll to a section on the landing page does not redirect back to the landing page in order to scroll to the desired section.
Solution
To solve this problem, we can implement a custom function handleRouteChange that handles both navigation and smooth scrolling, ensuring a seamless user experience.
const handleRouteChange = (e: any, path: string, section: string = "") => {
e.preventDefault();
if (path === "/") {
if (section) {
const sectionElement = document.getElementById(section);
if (sectionElement) {
sectionElement.scrollIntoView({ behavior: "smooth" });
}
}
} else {
navigate(path);
if (section) {
setTimeout(() => {
const sectionElement = document.getElementById(section);
if (sectionElement) {
sectionElement.scrollIntoView({ behavior: "smooth" });
}
}, 100);
}
}
setIsOpen(false);
};
Now to even understand much better, We'll create a basic navbar component with a few links, and apply minimal styling to focus on the functionality of sectional-based routing with smooth scrolling.
Here's the simplified version of the Navbar
component:
import { useState } from "react";
import { useNavigate } from "react-router-dom";
const Navbar: React.FunctionComponent = () => {
const navigate = useNavigate();
const [isOpen, setIsOpen] = useState<boolean>(false);
const handleRouteChange = (e: any, path: string, section: string = "") => {
e.preventDefault();
if (path === "/") {
if (section) {
const sectionElement = document.getElementById(section);
if (sectionElement) {
sectionElement.scrollIntoView({ behavior: "smooth" });
}
}
} else {
navigate(path);
if (section) {
setTimeout(() => {
const sectionElement = document.getElementById(section);
if (sectionElement) {
sectionElement.scrollIntoView({ behavior: "smooth" });
}
}, 100);
}
}
setIsOpen(false);
};
return (
<div className="w-full h-16 bg-gray-800 text-white fixed top-0 flex justify-between items-center px-4">
<div className="text-xl font-bold">MyApp</div>
<ul className="flex space-x-4">
<li>
<a className="cursor-pointer" onClick={(e) => handleRouteChange(e, "/", "home")}>
Home
</a>
</li>
<li>
<a className="cursor-pointer" onClick={(e) => handleRouteChange(e, "/", "about")}>
About
</a>
</li>
<li>
<a className="cursor-pointer" onClick={(e) => handleRouteChange(e, "/", "services")}>
Services
</a>
</li>
<li>
<a className="cursor-pointer" onClick={(e) => handleRouteChange(e, "/", "contact")}>
Contact
</a>
</li>
</ul>
</div>
);
};
export default Navbar;
Explanation
Basic Structure:
The Navbar contains a brand name and a list of navigation links. The handleRouteChange function handles the navigation and smooth scrolling.
Minimal Styling:
The navbar is styled with a background color (bg-gray-800) and text color (text-white).
The navbar is fixed at the top of the page (fixed top-0).
Links are styled with spacing (space-x-4) and cursor-pointer for the clickable effect.
Navigation Links:
Each navigation link calls the handleRouteChange function with the appropriate path and section parameters.
Usage
To see the smooth scrolling in action, ensure your landing page (root path /) has sections with corresponding id attributes (e.g., home, about, services, contact).
Here's the simplified version of the homepage
component:
import Hero from "@/components/Hero";
import About from "@/components/About";
import Services from "@/components/Services";
import Contact from "@/components/Contact";
const Home = () => {
return (
<div className="w-full overflow-hidden h-full flex flex-col">
<Hero />
<Services />
<About/>
<Contact />
</div>
)
}
export default Home
Here's the simplified version of the services
component:
import React from 'react'
const Services = () => {
return (
<div id="services" className='h-screen w-full'>Services</div>
)
}
export default Services
Here's the simplified version of the About
component:
import React from 'react'
const About = () => {
return (
<div id="about" className='h-screen w-full'>About</div>
)
}
export default About
Here's the simplified version of the Contact
component:
import React from 'react'
const Contact = () => {
return (
<div id="contact" className='h-screen w-full'>Cntact</div>
)
}
export default Contact
Now, when you click on the navigation links, the page will navigate to the appropriate section with a smooth scrolling effect, even if you are not currently on the landing page.
Conclusion
Enhancing user experience in a Single Page Application (SPA) is crucial, and seamless navigation with smooth scrolling is a game-changer. By implementing sectional-based routing, users can effortlessly navigate to specific sections on your landing page from any route within the app.
This method not only improves usability but also maintains a smooth and engaging user interface. The custom handleRouteChange
function ensures smooth transitions, making your app more intuitive and enjoyable to use.
Incorporating this technique is straightforward and highly effective, transforming your SPA into a user-friendly and responsive application. Elevate your app’s navigation experience and keep your users engaged and satisfied. Happy coding! 🚀