Client-Side Routing
Problem
Every navigation reloads the entire page, destroying application state and causing jarring white flashes. Users lose their place in forms, scroll positions reset, and interactive features restart from scratch. The experience feels slow and broken compared to native applications.
Solution
Use the History API
to update the URL and conditionally render components based on the current path, all without triggering browser navigation. This preserves application state, eliminates loading flashes, and creates instant transitions between views.
Example
This example shows a basic client-side routing implementation using the History API to navigate without page reloads.
// Update URL and render new content without page reload
function navigate(path) {
// Update browser history without triggering navigation
window.history.pushState({}, '', path);
// Re-render the app based on the new path
render(getCurrentRoute());
}
// Intercept all link clicks to use client-side navigation
document.querySelectorAll('a').forEach(link => {
link.addEventListener('click', (e) => {
// Prevent default browser navigation
e.preventDefault();
// Use our custom navigate function instead
navigate(link.pathname);
});
});
Benefits
- Eliminates page reloads for instant navigation and better user experience.
- Preserves application state across navigation including forms and scroll position.
- Creates smooth transitions between views without white flashes.
- Enables sophisticated UX patterns like animated page transitions.
- Reduces server load by avoiding full page refreshes.
Tradeoffs
- Requires JavaScript to function, breaking for users without it enabled.
- Initial page load includes routing logic and all route handling code.
- Must carefully manage memory to avoid leaks when components unmount.
- Server-side configuration needed to handle direct URL access and refreshes.
- Can complicate SEO and analytics tracking compared to traditional navigation.