Client Side Routing
React Router
RouterProvider
For our components to integrate with React Router, we must use the RouterProvider component. This is really only required if you want to utilize the included navigation functionality of our components.
This is achieved by wrapping your app, and providing the navigate function from React Router.
Here is a simplified example
import { Route, Routes, useNavigate } from "react-router";import { RouterProvider } from "@cfa/react-core";import { Home } from "./pages/Home";import { Layout } from "./Layout";import { Tabs } from "./pages/Tabs";
function App() { const navigate = useNavigate(); return ( <RouterProvider navigate={navigate}> <Routes> <Route element={<Layout />}> <Route index element={<Home />} /> <Route path="tabs/*" element={<Tabs />} /> </Route> </Routes> </RouterProvider> );}This will provide the navigate function to all of the components that provide navigation functionality, such as Tabs
Nested Routes
Here is how this would then work with the Tabs component.
You can use useLocation to set the selectedKey to ensure the active tab is selected based on the route.
export default function TabPage() { const { pathname } = useLocation();
return ( <Tabs selectedKey={pathname}> <Tabs.List aria-label="Custom Tabs"> <Tabs.Item id="/tabs/one" href="/tabs/one"> One </Tabs.Item> <Tabs.Item id="/tabs/two" href="/tabs/two"> Two </Tabs.Item> </Tabs.List> <Tabs.Panel id={pathname}> <Routes> <Route path="/" element={<One />} /> <Route path="/two" element={<Two />} /> </Routes> </Tabs.Panel> </Tabs> );}NextJS
"use client";
import { useRouter } from "next/navigation";import { RouterProvider } from "@cfa/react-core";
declare module "@cfa/react-core" { interface RouterConfig { routerOptions: NonNullable< Parameters<ReturnType<typeof useRouter>["push"]>[1] >; }}
export function ClientProviders({ children }: { children: React.ReactNode }) { const router = useRouter();
return <RouterProvider navigate={router.push}>{children}</RouterProvider>;}Then you can use the provider in your root application layout
import { ClientProviders } from "./provider";
export default function RootLayout({ children,}: Readonly<{ children: React.ReactNode;}>) { return ( <html lang="en"> <body> <main> <ClientProviders>{children}</ClientProviders> </main> </body> </html> );}If you are using the NextJS basePath, then you need to configure an environment variable to gain access to it.
const basePath = "...";const nextConfig = { basePath, env: { BASE_PATH: basePath, },};// ...
export function ClientProviders({ children }) { let router = useRouter(); let useHref = (href: string) => process.env.BASE_PATH + href;
return ( <RouterProvider navigate={router.push} useHref={useHref}> {children} </RouterProvider> );}Tanstack Router
For Tanstack Router, you can simply wrap the component as shown below and just use this throughout your app as opposed to importing directly from @cfa/react-core
import { createLink } from "@tanstack/react-router";import { Link as ReactAriaLink, MenuItem } from "@cfa/react-core";
export const Link = createLink(ReactAriaLink);export const MenuItemLink = createLink(MenuItem);We utilized the React Aria documentation for client side routing to provide our base. Please provide any feedback to the team so that we ensure we keep these docs updated with any CFA specific best practices and guidelines.