@rectify-dev/router
v2.5.0
Published
Client-side router for Rectify — inspired by React Router v6
Readme
@rectify-dev/router
Client-side router for Rectify — inspired by React Router v6. Provides BrowserRouter, HashRouter, nested routes, Outlet, Link, NavLink, and a full set of navigation hooks.
Installation
# npm
npm install @rectify-dev/core @rectify-dev/router
# pnpm
pnpm add @rectify-dev/core @rectify-dev/router
# yarn
yarn add @rectify-dev/core @rectify-dev/routerSetup
Vite
import { defineConfig } from "vite";
import rectify from "@rectify-dev/vite-plugin";
export default defineConfig({
plugins: [rectify()],
});TypeScript
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@rectify-dev/core"
}
}Quick start
import { createRoot } from "@rectify-dev/core";
import { BrowserRouter } from "@rectify-dev/router";
import App from "./App";
createRoot(document.getElementById("root")!).render(
<BrowserRouter>
<App />
</BrowserRouter>,
);import { Routes, Route, Link } from "@rectify-dev/router";
import Home from "./pages/Home";
import About from "./pages/About";
import User from "./pages/User";
export default function App() {
return (
<>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/users/:id" element={<User />} />
<Route path="*" element={<p>404 Not Found</p>} />
</Routes>
</>
);
}API Reference
BrowserRouter
Provides routing backed by the HTML5 History API (pushState / popstate). URLs look like /about, /users/42.
type BrowserRouterProps = {
children?: any;
basename?: string; // default "/"
};<BrowserRouter basename="/app">
<App />
</BrowserRouter>Use basename when your app is served from a sub-path (e.g. /app).
HashRouter
Provides routing backed by window.location.hash. URLs look like /#/about. No server configuration required.
type HashRouterProps = {
children?: any;
basename?: string;
};<HashRouter>
<App />
</HashRouter>Routes and Route
<Routes> renders the first <Route> whose path matches the current URL. <Route> itself renders null — it is a data carrier read by <Routes>.
type RouteProps = {
path?: string; // URL pattern, e.g. "/users/:id"
index?: boolean; // matches the parent path exactly
element?: RectifyNode;
children?: RectifyNode; // nested <Route>s
};<Routes>
{/* exact match */}
<Route path="/" element={<Home />} />
{/* URL param */}
<Route path="/users/:id" element={<UserProfile />} />
{/* catch-all */}
<Route path="*" element={<NotFound />} />
{/* layout route with nested children */}
<Route path="/settings" element={<SettingsLayout />}>
<Route index element={<GeneralSettings />} />
<Route path="profile" element={<ProfileSettings />} />
</Route>
</Routes>Outlet
Renders the matched child route's element inside a layout component.
import { Outlet } from "@rectify-dev/router";
function SettingsLayout() {
return (
<div>
<aside>
<NavLink to="/settings">General</NavLink>
<NavLink to="/settings/profile">Profile</NavLink>
</aside>
<main>
<Outlet /> {/* child route renders here */}
</main>
</div>
);
}Link
Client-side navigation anchor. Intercepts plain left-clicks to update the URL without a full page reload. Modified clicks (Ctrl / Cmd / Shift / Alt) and middle-button clicks are passed through.
type LinkProps = {
to: string;
replace?: boolean;
state?: unknown;
children?: RectifyNode;
className?: string;
style?: CSSProperties;
onClick?: (e: SyntheticMouseEvent) => void;
};<Link to="/about">About</Link>
<Link to="/checkout" replace state={{ from: "/cart" }}>Checkout</Link>NavLink
Like Link but applies activeClassName when the current path matches to.
type NavLinkProps = LinkProps & {
activeClassName?: string; // default "active"
end?: boolean; // default true
};{/* exact match */}
<NavLink to="/settings">Settings</NavLink>
{/* active on /blog and any sub-path */}
<NavLink to="/blog" end={false} activeClassName="current">
Blog
</NavLink>Navigate
Renders null but triggers a navigation as a side-effect. Useful for redirect-on-render patterns.
type NavigateProps = {
to: string;
replace?: boolean;
state?: unknown;
};function ProtectedRoute({ isLoggedIn }: { isLoggedIn: boolean }) {
if (!isLoggedIn) {
return <Navigate to="/login" replace />;
}
return <Dashboard />;
}useNavigate
Returns the navigate function for programmatic navigation.
type NavigateFunction = {
(to: string, options?: NavigateOptions): void;
(delta: number): void; // go(-1) = back, go(1) = forward
};
type NavigateOptions = {
replace?: boolean;
state?: unknown;
};const navigate = useNavigate();
// push
navigate("/dashboard");
// replace
navigate("/login", { replace: true });
// go back
navigate(-1);useLocation
Returns the current RouterLocation. Re-renders whenever the location changes.
type RouterLocation = {
pathname: string;
search: string; // includes "?" e.g. "?q=hello"
hash: string;
state: unknown;
key: string;
};const location = useLocation();
console.log(location.pathname); // e.g. "/users/42"useParams
Returns URL params extracted by the nearest matching <Route>.
// Route: <Route path="/users/:id/posts/:postId" element={<Post />} />
const { id, postId } = useParams<{ id: string; postId: string }>();useMatch
Tries to match a pattern against the current pathname. Returns a PathMatch on success, or null.
type PathMatch = {
params: Record<string, string>;
pathname: string; // matched portion
};const match = useMatch("/users/:id");
if (match) {
console.log(match.params.id);
}useSearchParams
Returns [URLSearchParams, setter]. Calling the setter navigates to the current path with a new query string.
const [params, setParams] = useSearchParams();
// read
console.log(params.get("q"));
// write — navigates to ?q=hello&page=1
setParams({ q: "hello", page: "1" });useHref
Resolves a to path to a full href string respecting the router's basename and the current location.
const href = useHref("/about"); // "/about" with BrowserRouter, "/#/about" with HashRouterURL patterns
| Pattern | Matches |
|---------|---------|
| /about | Exactly /about |
| /users/:id | /users/42, /users/alice |
| /files/* | /files/, /files/a/b/c |
| * | Everything (catch-all) |
Nested routes example
function App() {
return (
<BrowserRouter>
<Routes>
{/* Layout route */}
<Route path="/" element={<RootLayout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
{/* Nested layout */}
<Route path="users" element={<UsersLayout />}>
<Route index element={<UserList />} />
<Route path=":id" element={<UserProfile />} />
</Route>
</Route>
</Routes>
</BrowserRouter>
);
}License
MIT
