Next generation React routing library with accessible navigation and focus management.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Advanced routing patterns including redirects, conditional rendering, and route matching utilities.
Declarative redirect component for programmatic navigation during rendering.
/**
* Declarative redirect component for programmatic navigation
* @param props - Redirect configuration
*/
function Redirect(props: {
from?: string;
to: string;
replace?: boolean;
state?: any;
noThrow?: boolean;
}): React.ReactElement;Props:
from (string, optional) - Source path pattern (only used inside Router)to (string, required) - Destination pathreplace (boolean, optional) - Replace current history entry (defaults to true)state (any, optional) - State to pass with redirectnoThrow (boolean, optional) - Don't throw redirect error (for server rendering)Usage Examples:
import React from "react";
import { Router, Redirect } from "@reach/router";
// Basic redirect
const App = () => (
<Router>
<Home path="/" />
<Redirect from="/home" to="/" />
<About path="/about" />
</Router>
);
// Redirect with parameters
const App = () => (
<Router>
<UserProfile path="/users/:userId" />
<Redirect from="/profile/:userId" to="/users/:userId" />
</Router>
);
// Conditional redirect based on authentication
const ProtectedRoute = ({ component: Component, ...props }) => {
const isAuthenticated = useAuth();
if (!isAuthenticated) {
return <Redirect to="/login" state={{ from: props.path }} />;
}
return <Component {...props} />;
};
<Router>
<Login path="/login" />
<ProtectedRoute component={Dashboard} path="/dashboard" />
</Router>
// Redirect with state
const LoginRedirect = () => (
<Redirect
to="/dashboard"
state={{ message: "Successfully logged in!" }}
/>
);
// Server-safe redirect
const ServerSafeRedirect = ({ to }) => (
<Redirect to={to} noThrow />
);
// Multiple redirects for old URLs
const LegacyRedirects = () => (
<Router>
<Home path="/" />
<Redirect from="/old-home" to="/" />
<Redirect from="/legacy/about" to="/about" />
<Redirect from="/v1/users/:id" to="/users/:id" />
<About path="/about" />
<User path="/users/:id" />
</Router>
);Render prop component for conditional rendering based on path matching without routing.
/**
* Render prop component for conditional rendering based on path matching
* @param props - Match configuration
*/
function Match(props: {
path: string;
children: (props: MatchRenderProps) => React.ReactNode;
}): React.ReactElement;
interface MatchRenderProps {
navigate: (to: string | number, options?: NavigateOptions) => Promise<void>;
location: Location;
match: MatchResult | null;
}
interface MatchResult {
uri: string; // Always normalized with leading slash
path: string;
[paramName: string]: string | string[]; // Can contain arrays for splat routes
}Usage Examples:
import React from "react";
import { Match } from "@reach/router";
// Conditional navigation based on match
const ConditionalNav = () => (
<Match path="/admin/*">
{({ match }) => (
<nav>
<Link to="/">Home</Link>
{match && (
<>
<Link to="/admin/users">Users</Link>
<Link to="/admin/settings">Settings</Link>
</>
)}
</nav>
)}
</Match>
);
// Dynamic styling based on path match
const Header = () => (
<Match path="/products/*">
{({ match, location }) => (
<header className={match ? "products-header" : "default-header"}>
<h1>My Store</h1>
{match && <p>Browsing: {location.pathname}</p>}
</header>
)}
</Match>
);
// Multiple matches for complex layouts
const Layout = ({ children }) => (
<div>
<Match path="/dashboard/*">
{({ match }) => match && <DashboardSidebar />}
</Match>
<Match path="/admin/*">
{({ match }) => match && <AdminToolbar />}
</Match>
<main>{children}</main>
</div>
);
// Match with parameter extraction
const BreadcrumbTrail = () => (
<Match path="/users/:userId/posts/:postId">
{({ match, navigate }) => {
if (!match) return null;
const { userId, postId } = match;
return (
<nav className="breadcrumb">
<button onClick={() => navigate("/")}>Home</button>
<span> / </span>
<button onClick={() => navigate("/users")}>Users</button>
<span> / </span>
<button onClick={() => navigate(`/users/${userId}`)}>
User {userId}
</button>
<span> / </span>
<span>Post {postId}</span>
</nav>
);
}}
</Match>
);
// Conditional component mounting
const FeatureToggle = ({ feature, children }) => (
<Match path={`/features/${feature}/*`}>
{({ match }) => match ? children : null}
</Match>
);
<FeatureToggle feature="beta">
<BetaFeatures />
</FeatureToggle>Programmatic route matching utility for checking if a path matches a pattern outside of components.
/**
* Programmatic route matching utility
* @param path - Path pattern to match against
* @param uri - URI to test for matching
* @returns Match result with params and uri, or null if no match
*/
function matchPath(path: string, uri: string): MatchResult | null;
interface MatchResult {
route: {
path: string;
};
params: Record<string, string | string[]>; // Can contain arrays for splat routes
uri: string; // Always normalized with leading slash
}Usage Examples:
import { matchPath } from "@reach/router";
// Basic path matching
const match = matchPath("/users/:userId", "/users/123");
if (match) {
console.log(match.params.userId); // "123"
console.log(match.uri); // "/users/123"
}
// Wildcard matching
const wildcardMatch = matchPath("/files/*", "/files/docs/readme.txt");
if (wildcardMatch) {
console.log(wildcardMatch.params["*"]); // "docs/readme.txt"
}
// Route-based data fetching
const fetchRouteData = async (pathname) => {
const userMatch = matchPath("/users/:userId", pathname);
if (userMatch) {
return await fetchUser(userMatch.params.userId);
}
const postMatch = matchPath("/posts/:postId", pathname);
if (postMatch) {
return await fetchPost(postMatch.params.postId);
}
return null;
};
// Server-side route matching
const getServerSideProps = async (context) => {
const { req } = context;
const pathname = req.url;
const match = matchPath("/products/:productId", pathname);
if (match) {
const product = await fetchProduct(match.params.productId);
return { props: { product } };
}
return { props: {} };
};
// Route guards and middleware
const routeGuards = [
{
pattern: "/admin/*",
guard: (match, user) => user?.isAdmin
},
{
pattern: "/users/:userId/*",
guard: (match, user) => user?.id === match.params.userId
}
];
const checkAccess = (pathname, user) => {
for (const { pattern, guard } of routeGuards) {
const match = matchPath(pattern, pathname);
if (match && !guard(match, user)) {
return false;
}
}
return true;
};
// Dynamic route configuration
const routes = [
{ pattern: "/", component: "Home" },
{ pattern: "/about", component: "About" },
{ pattern: "/users/:userId", component: "UserProfile" },
{ pattern: "/posts/:postId", component: "PostDetail" }
];
const findMatchingRoute = (pathname) => {
for (const route of routes) {
const match = matchPath(route.pattern, pathname);
if (match) {
return { ...route, match };
}
}
return null;
};Utility functions for handling redirects programmatically.
/**
* Check if an error is a redirect request
* @param error - Error object to check
* @returns True if error is a redirect request
*/
function isRedirect(error: any): boolean;
/**
* Throw a redirect request for error boundary handling
* @param to - Destination path
* @throws RedirectRequest that can be caught by error boundaries
*/
function redirectTo(to: string): never;Usage Examples:
import { isRedirect, redirectTo } from "@reach/router";
// Error boundary handling redirects
class RedirectBoundary extends React.Component {
componentDidCatch(error, errorInfo) {
if (isRedirect(error)) {
// Handle redirect in error boundary
console.log("Caught redirect to:", error.uri);
// The redirect will be handled automatically
} else {
// Handle other errors
console.error("Component error:", error);
}
}
render() {
return this.props.children;
}
}
// Programmatic redirects in components
const AuthCheck = ({ children }) => {
const user = useAuth();
React.useEffect(() => {
if (!user) {
// Throw redirect that will be caught by LocationProvider
redirectTo("/login");
}
}, [user]);
return user ? children : null;
};
// Conditional redirects in render
const ConditionalRedirect = ({ condition, to, children }) => {
if (condition) {
redirectTo(to);
}
return children;
};
// Redirect with data validation
const ValidatedRoute = ({ data, fallback, children }) => {
React.useEffect(() => {
if (!data || !data.isValid) {
redirectTo(fallback);
}
}, [data, fallback]);
return data?.isValid ? children : null;
};
// Error handling with redirect detection
const handleAsyncAction = async () => {
try {
await performAction();
} catch (error) {
if (isRedirect(error)) {
// Don't log redirect errors
return;
}
// Log and handle other errors
console.error("Action failed:", error);
redirectTo("/error");
}
};
// Custom redirect hook
const useRedirectIf = (condition, to) => {
React.useEffect(() => {
if (condition) {
redirectTo(to);
}
}, [condition, to]);
};
// Usage of custom hook
const ProtectedComponent = () => {
const user = useAuth();
useRedirectIf(!user, "/login");
return <div>Protected content</div>;
};Complex routing patterns and techniques for sophisticated applications.
Usage Examples:
// Route-based code splitting
const LazyRoute = ({ component, ...props }) => {
const [Component, setComponent] = React.useState(null);
React.useEffect(() => {
import(`../components/${component}`)
.then(module => setComponent(() => module.default));
}, [component]);
if (!Component) {
return <div>Loading...</div>;
}
return <Component {...props} />;
};
<Router>
<LazyRoute component="Home" path="/" />
<LazyRoute component="About" path="/about" />
</Router>
// Nested routing with context
const NestedRoutes = () => (
<Router>
<Dashboard path="/dashboard/*">
<DashboardHome path="/" />
<Settings path="/settings/*">
<GeneralSettings path="/" />
<SecuritySettings path="/security" />
<ProfileSettings path="/profile" />
</Settings>
</Dashboard>
</Router>
);
// Route-based theming
const ThemedRouter = () => {
const location = useLocation();
const theme = getThemeForPath(location.pathname);
return (
<ThemeProvider theme={theme}>
<Router>
<Home path="/" />
<Admin path="/admin/*" />
<Public path="/public/*" />
</Router>
</ThemeProvider>
);
};
// Dynamic route generation
const DynamicRoutes = ({ routes }) => (
<Router>
{routes.map(route => {
const Component = route.component;
return (
<Component
key={route.path}
path={route.path}
{...route.props}
/>
);
})}
</Router>
);
// Route transition animations
const AnimatedRouter = ({ children }) => {
const location = useLocation();
return (
<TransitionGroup>
<CSSTransition
key={location.pathname}
classNames="route"
timeout={300}
>
<Router location={location}>
{children}
</Router>
</CSSTransition>
</TransitionGroup>
);
};Install with Tessl CLI
npx tessl i tessl/npm-reach--router