@void-snippets/react

defineRoute & build()

Route definitions, metadata, search params, and URL construction.

#defineRoute(path, config?)

Defines a single route with a path and optional metadata. Chain .search() to declare typed search parameters.

#Metadata fields (config)

FieldTypeDescription
permissionsstring[]Access control identifiers — read via route.handle in your router config.
breadcrumbstringLabel for breadcrumb navigation.
titlestringPage title for management.
metaRecordAny custom metadata — loader IDs, analytics events, feature flags.

#.search() — typed search params

Chain immediately after defineRoute(). The generic T declares which search params this route accepts.

typescript
defineRoute('/contacts')
  .search<{ page: number; sort?: 'asc' | 'desc'; q?: string }>()

Use absolute paths. Write /dashboard/users not ${DASHBOARD}/${USERS}. TypeScript extracts path parameter names (:userId) using template literal inference, and concatenated strings cause exponential type-checking in large apps.

#build() — constructing URLs

TypeScript shapes the build() signature based on what the route has.

Route shapeSignature
No params, no searchbuild() → string
Optional-only searchbuild(options?) → string
Required path parambuild({ params }) → string
Required search keybuild({ search }) → string
typescript
// No arguments — simple route
AppRoutes.dashboard.settings.build()
// → '/dashboard/settings'

// Optional search
AppRoutes.auth.login.build({ search: { redirect: '/dashboard' } })
// → '/auth/login?redirect=%2Fdashboard'

// Required path param
AppRoutes.dashboard.users.detail.build({ params: { userId: '123' } })
// → '/dashboard/users/123'

// Required path param + optional search
AppRoutes.dashboard.users.detail.build({
  params: { userId: '123' },
  search: { tab: 'settings' },
})
// → '/dashboard/users/123?tab=settings'

// TypeScript catches these at compile time:
AppRoutes.dashboard.users.detail.build()                            // ❌ params required
AppRoutes.dashboard.users.list.build()                              // ❌ search.page required
AppRoutes.dashboard.users.list.build({ search: { page: '1' } })    // ❌ page must be number

#Wiring React Router

typescript
// router.tsx
import { createBrowserRouter } from 'react-router';
import { AppRoutes } from './routes';

const router = createBrowserRouter([
  {
    path:    AppRoutes.auth.login.path,
    element: <LoginPage />,
  },
  {
    path:    AppRoutes.dashboard.root.path,
    element: <DashboardLayout />,
    handle:  { title: AppRoutes.dashboard.root.title, breadcrumb: AppRoutes.dashboard.root.breadcrumb },
    children: [
      {
        path:    AppRoutes.dashboard.users.list.path,
        element: <UsersListPage />,
        handle:  { permissions: AppRoutes.dashboard.users.list.permissions },
      },
    ],
  },
]);
tsx
// Programmatic
const navigate = useNavigate();
navigate(AppRoutes.dashboard.users.detail.build({ params: { userId: contact._id } }));

// Link component
<Link to={AppRoutes.auth.login.build({ search: { redirect: location.pathname } })}>
  Log in
</Link>