@page-speed/router
Lightweight, SSR-compatible routing for the OpenSite website platform. Native browser routing with zero dependencies, tree-shakable exports, and < 3KB gzipped.


Features
- 🚀 Ultra-lightweight: < 3KB minified + gzipped
- 🔥 SSR-safe: Built for server-side rendering with proper hydration
- 🌲 Tree-shakable: Import only what you need
- 🎯 Native browser APIs: Uses History API and window.location
- 📦 Zero dependencies: Only React as peer dependency
- ⚡ Performance-first: Optimized for Core Web Vitals
- 🎨 TypeScript: Full type safety
- 🧩 Modular: Hooks work independently, provider optional
Installation
npm install @page-speed/router
pnpm add @page-speed/router
yarn add @page-speed/router
Quick Start
Basic Navigation (No Provider Required)
Many hooks work without any provider setup:
import { useNavigation, useUrl } from '@page-speed/router';
function App() {
const { navigateTo } = useNavigation();
const { pathname } = useUrl();
return (
<div>
<p>Current path: {pathname}</p>
<button onClick={() => navigateTo('/about')}>
Go to About
</button>
</div>
);
}
With RouterProvider (For Dynamic Params)
import { RouterProvider, useParams } from '@page-speed/router';
const routes = [
{ path: '/' },
{ path: '/blog/:slug' },
{ path: '/products/:category/:id' }
];
function App() {
return (
<RouterProvider routes={routes}>
<BlogPost />
</RouterProvider>
);
}
function BlogPost() {
const { slug } = useParams();
return <div>Blog post: {slug}</div>;
}
Core Hooks
useUrl()
Get current URL information. Works without RouterProvider.
const {
href,
pathname,
search,
hash,
origin,
host,
hostname,
port,
protocol
} = useUrl();
useNavigation()
Programmatic navigation. Works without RouterProvider.
const { navigateTo, replace, reload } = useNavigation();
navigateTo('/about');
navigateTo({
path: '/blog',
anchor: 'comments',
replace: false,
smooth: true,
state: { from: 'home' }
});
replace('/new-path');
reload();
useGoBack()
Safe back navigation with fallback.
const { goBack, canGoBack } = useGoBack({
fallback: '/home'
});
goBack();
goBack(-2);
<button disabled={!canGoBack}>Back</button>
useParams()
Extract dynamic route parameters. Requires RouterProvider with routes.
const params = useParams();
const allParams = useParams(true);
useRouteMatch()
Check if current path matches a pattern.
const match = useRouteMatch('/blog/:slug');
if (match.isMatch) {
console.log(match.params);
}
Utility Hooks
usePathname()
const pathname = usePathname();
useSearchParams()
const params = useSearchParams();
useHash()
const hash = useHash();
useUpdateSearchParams()
const updateParams = useUpdateSearchParams();
updateParams({ page: '2', sort: 'date' });
updateParams({ category: null });
updateParams({ page: '3' }, true);
SSR Setup
Rails Integration
<!-- customer_websites/chai_index.html.erb -->
<script>
window.__ROUTER_INITIAL_STATE__ = {
path: '<%= @initial_path %>',
params: <%= @initial_params.to_json %>
};
</script>
<div id="root"></div>
import { RouterProvider } from '@page-speed/router';
const initialState = window.__ROUTER_INITIAL_STATE__;
ReactDOM.hydrateRoot(
document.getElementById('root'),
<RouterProvider
initialPath={initialState.path}
routes={routes}
>
<App />
</RouterProvider>
);
Next.js Integration
import { RouterProvider } from '@page-speed/router';
export default function App({ Component, pageProps, router }) {
return (
<RouterProvider initialPath={router.pathname}>
<Component {...pageProps} />
</RouterProvider>
);
}
Anchor Navigation
Automatic smooth scrolling to anchors:
const { navigateTo } = useNavigation();
navigateTo({
path: '/docs',
anchor: 'installation'
});
navigateTo({ anchor: 'features' });
navigateTo({
path: '/about',
anchor: 'team',
smooth: false
});
Advanced Usage
Custom Route Matching
import { matchPath, buildPath } from '@page-speed/router';
const match = matchPath('/blog/hello', '/blog/:slug');
const path = buildPath('/blog/:slug', { slug: 'world' });
Multiple Route Patterns
import { useMultiMatch } from '@page-speed/router';
const match = useMultiMatch([
{ pattern: '/blog/:slug' },
{ pattern: '/products/:id' },
{ pattern: '/', exact: true }
]);
if (match?.path.startsWith('/blog')) {
}
Navigation Events
<RouterProvider
onNavigate={(path) => {
analytics.track('page_view', { path });
}}
>
<App />
</RouterProvider>
API Reference
RouterProvider Props
children | ReactNode | - | Child components |
initialPath | string | - | Initial path for SSR |
routes | Route[] | [] | Route patterns for param extraction |
scrollBehavior | 'smooth' | 'auto' | 'smooth' | Default scroll behavior |
onNavigate | (path: string) => void | - | Navigation callback |
Route Object
interface Route {
path: string;
exact?: boolean;
}
Performance
- Bundle Size: < 3KB minified + gzipped
- Tree-shaking: Import individual hooks for smaller bundles
- No Re-renders: Optimized context updates
- Lazy Loading: Dynamic imports for code splitting
- 60fps Scrolling: Smooth anchor navigation
Browser Support
- Chrome/Edge 88+
- Firefox 78+
- Safari 14+
- Chrome Android 88+
- Safari iOS 14+
Requires History API and IntersectionObserver support.
Migration Guide
From React Router
import { useNavigate, useParams } from 'react-router-dom';
const navigate = useNavigate();
navigate('/about');
import { useNavigation, useParams } from '@page-speed/router';
const { navigateTo } = useNavigation();
navigateTo('/about');
From Next.js Router
import { useRouter } from 'next/router';
const router = useRouter();
router.push('/about');
import { useNavigation } from '@page-speed/router';
const { navigateTo } = useNavigation();
navigateTo('/about');
TypeScript
Full TypeScript support with exported types:
import type {
UrlState,
NavigateOptions,
RouteParams,
Route
} from '@page-speed/router';
Contributing
See CONTRIBUTING.md for development setup and guidelines.
License
BSD-3-Clause
Support
Built with ❤️ for the OpenSite ecosystem