--- name: rasengan-routing description: Router definition and navigation patterns for Rasengan.js. Covers config-based and file-based routing, RouterComponent, defineRouter, defineRoutesGroup, Link, NavLink, useLocation, useNavigate, useParams, useSearchParams, dynamic routes, route groups, and file-based routing conventions. Use when creating or modifying app.router.ts, defining route structures, setting up dynamic segments, or implementing navigation. license: MIT metadata: author: dilane3 framework: rasengan version: '2.0.0' --- # Rasengan.js Routing Patterns ## When to Activate - Creating or editing `src/app/app.router.{js,ts}` - Choosing between config-based and file-based routing - Defining navigation links with `Link` or `NavLink` - Using navigation hooks: `useNavigate`, `useLocation`, `useParams`, `useSearchParams` - Defining dynamic route segments `[param]`, `[_param]`, route groups `(group)` - Setting up nested routers or route groups with `defineRoutesGroup` - Customizing 404 / loading fallbacks at the router level ## RouterComponent Properties | Property | Type | Description | | ------------------- | -------------------------------- | ------------------------------- | | `layout` | `LayoutComponent \| RouteNode` | Layout component for the router | | `routers` | `RouterComponent[]` | Nested sub-routers | | `pages` | `PageComponent[] \| RouteNode[]` | Page components | | `loaderComponent` | `FunctionComponent` | Loading fallback | | `notFoundComponent` | `FunctionComponent` | 404 component | | `useParentLayout` | `boolean` | Inherit parent layout | ## Config-based Routing ```ts import { RouterComponent, defineRouter } from 'rasengan'; import Home from './home.page'; import About from './about.page'; import AppLayout from './layout'; class AppRouter extends RouterComponent {} export default defineRouter({ layout: AppLayout, pages: [Home, About], notFoundComponent: NotFound, })(AppRouter); ``` ## File-based Routing ```ts import { RouterComponent, defineRouter } from 'rasengan'; import Router from 'virtual:rasengan/router'; class AppRouter extends RouterComponent {} export default defineRouter({ imports: [Router] })(AppRouter); ``` ## Route Groups with defineRoutesGroup ```ts import { defineRoutesGroup } from 'rasengan'; export default defineRoutesGroup({ path: '/dashboard', pages: [Settings, Profile], routers: [AdminRouter], }); ``` ## Dynamic Route Conventions | File pattern | Route segment | Example URL | | -------------------------- | ----------------- | ----------------- | | `[id].page.tsx` | `:id` | `/posts/123` | | `[_locale]/index.page.tsx` | `:locale?` | `/en` or `/` | | `(group)/index.page.tsx` | (ignored in path) | `/` | | `_optional/index.page.tsx` | `optional?` | `/optional` or `` | Config-based dynamic routes use react-router syntax: ```ts Profile.path = '/profile/:id'; // required param Profile.path = '/profile/:id?'; // optional param Profile.path = '/profile/:id?/:name?'; // multiple optional params ``` ## Link Component Import from `rasengan` for client-side navigation: ```tsx import { Link } from 'rasengan'; // Basic usage Go to Dashboard // Dynamic routes Read More // Hash anchors (renders as , not react-router Link) Section // Fragment navigation with hash Statistics ``` The `Link` component renders an `` element that navigates client-side without a full page reload. ## NavLink Component Import from `rasengan` for links with active state tracking: ```tsx import { NavLink } from 'rasengan'; // Basic usage with className callback isPending ? "pending" : isActive ? "active" : "" } > About // Children as render props {({ isActive }) => ( Tasks )} ``` Active state matching: | NavLink | URL | `isActive` | | ----------------------------- | ------------ | ---------- | | `` | `/tasks` | `true` | | `` | `/tasks/123` | `true` | | `` | `/tasks` | `true` | | `` | `/tasks/123` | `false` | - `isActive` — `true` when current route **starts with** `to` value - `isPending` — `true` when the route transition is loading - `end` prop — restricts active matching to exact match only ## useNavigate Hook Import from `rasengan` for programmatic navigation: ```tsx import { useNavigate } from 'rasengan'; function LogoutButton() { const navigate = useNavigate(); const handleLogout = async () => { await logout(); navigate('/sign-in'); }; return ; } ``` - `navigate(to)` — navigate to a path - `navigate(-1)` — go back in history - `navigate(1)` — go forward in history - Supports all react-router `NavigateOptions` (`replace`, `state`, etc.) ## useLocation Hook Import from `rasengan` to read the current URL location: ```tsx import { useLocation } from 'rasengan'; function ActiveLink({ to, children }) { const { pathname } = useLocation(); return ( {children} ); } ``` Returns a location object with `pathname`, `search`, `hash`, `state`, and `key` properties. ## useParams Hook Import from `rasengan` to access dynamic route parameters: ```tsx import { useParams } from 'rasengan'; const Profile = () => { const { id } = useParams(); return
User ID: {id}
; }; Profile.path = '/profile/:id'; ``` - Returns an object where keys match the dynamic segment names in the route path - Optional params (`:id?`) may be `undefined` - Works in both config-based and file-based routing ## useSearchParams Hook Import from `rasengan` (re-exported from react-router) to read and update URL query string: ```tsx import { useSearchParams } from 'rasengan'; function FilterBar() { const [searchParams, setSearchParams] = useSearchParams(); const tab = searchParams.get('tab') ?? 'overview'; return (

Active tab: {tab}

); } ``` `setSearchParams` accepts multiple forms: ```tsx // Search param string setSearchParams('?tab=1'); // Shorthand object setSearchParams({ tab: '1' }); // Object with array values (multiple values for same key) setSearchParams({ brand: ['nike', 'reebok'] }); // Array of tuples setSearchParams([['tab', '1']]); // Function callback (receives current URLSearchParams) setSearchParams((prev) => { prev.set('tab', '2'); return prev; }); // With navigation options (prevent scroll reset, replace history) setSearchParams({ tab: '2' }, { replace: true, preventScrollReset: true }); ``` - `searchParams` is a stable `URLSearchParams` reference (safe as useEffect dependency) - `setSearchParams` causes a navigation — URL updates and re-render triggers - Optional `defaultInit` provides default values without changing the URL on first render - Function callback does NOT support React's setState queueing — multiple calls in same tick won't build on prior value ## Rules - Always create a class extending `RouterComponent` and wrap it with `defineRouter()` - Config-based: list all pages in `pages` array, set `layout` explicitly, provide `notFoundComponent` - File-based: use `import Router from 'virtual:rasengan/router'` with `{ imports: [Router] }` - Use `routers` for nested sub-routers when splitting large route trees - Set `useParentLayout: true` on child routers to inherit the parent's layout - Use `defineRoutesGroup` to group routes under a shared path prefix without a separate router class - Optional segments `[_param]` generate both with and without the segment - Route groups `(group)` do not add a path segment — use them for organization only - Underscore-prefixed directories `_name/` become optional path segments - Do NOT import directly from `react-router` — import routing APIs from `rasengan` - Use `NavLink` over `Link` + `useLocation` when you need active state tracking (less boilerplate) - Set `end` prop on `NavLink` when active state should only match the exact path, not sub-routes - Use `useSearchParams` instead of manual URL parsing for query string access - Prefer `Link` for declarative navigation and `useNavigate` for imperative navigation (e.g., after form submission)