Client Side Routing

React Aria components like Link, Menu, and Tabs function as navigational links with `href`, supporting attributes like target and download.

Introduction

React Aria components such as Link, Menu, Tabs, and Table transform elements into clickable links that navigate when clicked. These components utilize the href prop to render as an <a> tag, supporting attributes like target and download.

User interactions with these links vary by component. For instance, one might use arrow keys to navigate tabs or press enter to open a link within a ComboBox. With the href prop, React Aria facilitates seamless navigation for each component.

Typically, links perform the default browser action when clicked. However, many applications employ client-side routers to prevent full page reloads. The RouterProvider configures React Aria components to integrate with your client-side router. Simply set it up at the root, and any React Aria component with an href will automatically utilize your router.

Note that links to external sites will default to the browser's native navigation, and links not targeting "_self", using the download attribute, or modified with keys like Command or Alt, will also follow the browser's native behavior.

Router Provider

The RouterProvider component accepts two properties: navigate and useHref. Assign navigate to a function from your routing framework that handles client-side navigation. useHref is optional and modifies a router-specific href to a standard HTML href, such as by adding a base path. Below are setup examples for various frameworks.

import { RouterProvider } from 'react-aria-components';
import { useNavigate, useHref } from 'your-router';
 
export default function Layout() {
  let navigate = useNavigate();
 
  return (
    <RouterProvider navigate={navigate} useHref={useHref}>
      {/* ... */}
    </RouterProvider>
  );
}

Inertia.js

To integrate with Inertia.js, you must first declare it in your .d.ts file, such as in global.d.ts.

import {
  type FormDataConvertible,
  type Method,
  type PreserveStateOption,
  type Progress
} from '@inertiajs/core'
 
declare module 'react-aria-components' {
  interface RouterConfig {
    routerOptions: {
      method?: Method
      data?: Record<string, FormDataConvertible>
      replace?: boolean
      preserveState?: PreserveStateOption
      preserveScroll?: PreserveStateOption
      forceFormData?: boolean
      only?: string[]
      onBefore?: () => void
      onStart?: () => void
      onProgress?: (progress: Progress) => void
      onCancel?: () => void
      onSuccess?: () => void
      onError?: () => void
      onFinish?: () => void
    }
  }
}

Next, execute php artisan ziggy:generate to generate the Ziggy routes.

Then, proceed to alias 'ziggy-js' in your vite.config.ts file.

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';
import { resolve } from 'path';
 
export default defineConfig({
    plugins: [
        laravel({
            input: 'resources/js/app.tsx',
            ssr: 'resources/js/ssr.tsx',
            refresh: true,
        }),
        react(),
    ],
    resolve: {
      alias: {
        'ziggy-js': resolve('vendor/tightenco/ziggy'),
      }
    }
});

Next, in your resources/js/app.tsx you can encapsulate <App/> within RouterProvider as follows:

import './bootstrap';
import '../css/app.css';
 
import { createRoot, hydrateRoot } from 'react-dom/client';
import { createInertiaApp, router } from '@inertiajs/react';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { RouterProvider } from 'react-aria-components'
 
import { Ziggy } from '@/ziggy'
import { useRoute } from 'ziggy-js'
 
const appName = import.meta.env.VITE_APP_NAME || 'Laravel';
 
createInertiaApp({
  title: (title) => `${title} - ${appName}`,
  resolve: (name) => resolvePageComponent(`./Pages/${name}.tsx`, import.meta.glob('./Pages/**/*.tsx')),
  setup({ el, App, props }) {
    window.route = useRoute(Ziggy as any)
    const appElement = (
      <RouterProvider navigate={(to, options) => router.visit(to, options as any)}>
        <App {...props} />
      </RouterProvider>
    )
 
    if (import.meta.env.DEV) {
      createRoot(el).render(appElement);
      return
    }
 
    hydrateRoot(el, appElement);
  },
  progress: {
    color: '#4B5563',
  },
});

Next.js

The useRouter hook from next/navigation provides a router object for navigation purposes. The RouterProvider should be implemented in a client component at the root of each page or layout that contains React Aria links. Create a new client component in the app folder named provider.tsx for this purpose or combine it with other top-level providers as outlined in the Next.js documentation.

'use client';
 
import { useRouter } from 'next/navigation';
import { RouterProvider as RouterProviderPrimitive } from 'react-aria-components';
 
declare module 'react-aria-components' {
  interface RouterConfig {
    routerOptions: NonNullable<
      Parameters<ReturnType<typeof useRouter>['push']>[1]
    >;
  }
}
 
export function RouteProvider({ children }) {
  let router = useRouter();
 
  return (
    <RouterProviderPrimitive navigate={router.push}>
      {children}
    </RouterProviderPrimitive>
  );
}

Then, in app/layout.tsx or your main layout file, enclose the children components within the ClientProviders component.

import { RouteProvider } from './provider';
export default function RootLayout({children}) {
  return (
    <html>
      <body>
        <RouteProvider>{children}</RouteProvider>
      </body>
    </html>
  );
}

Remix

For Remix, we can use the useNavigate and useHref hooks. First, let's create a a file route-provider.tsx in app/components folder.

For comprehensive details, consult the Remix documentation.

Then in app/root.tsx or your main layout file you can use the RouteProvider component to encompass all pages.

Others

If you are using a different framework or router provider not mentioned above, refer to the React Aria Components Docs for additional information on integrating React Aria components with various routers and frameworks.