From 2e988778763492d7780fc607a831b7941edf058d Mon Sep 17 00:00:00 2001 From: Rob Hannay Date: Tue, 28 Apr 2026 14:10:25 +0000 Subject: [PATCH 1/3] =?UTF-8?q?docs:=20restore=20client=20side=20routing?= =?UTF-8?q?=20/=20RouterProvider=20section=20in=20frameworks.mdx=20?= =?UTF-8?q?=E2=99=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous `routing.html` page covered `RouterProvider` setup in detail (general API, React Router, Next.js app/pages router, Remix, TanStack Router) but is no longer linked from the new docs and `react-aria.adobe.com/routing` returns 404. The new `frameworks.mdx` page only mentions `RouterProvider` in passing inside the React Router (framework mode) tab and does not explain how to set it up. This restores the old detailed routing content as a 'Client side routing' section at the top of `frameworks.mdx`, ahead of the existing locale and bundler tabs (now grouped under 'Locale and bundler setup'). Co-authored-by: Rook --- .../s2-docs/pages/react-aria/frameworks.mdx | 269 ++++++++++++++++++ 1 file changed, 269 insertions(+) diff --git a/packages/dev/s2-docs/pages/react-aria/frameworks.mdx b/packages/dev/s2-docs/pages/react-aria/frameworks.mdx index 04c1288126c..17c64672d99 100644 --- a/packages/dev/s2-docs/pages/react-aria/frameworks.mdx +++ b/packages/dev/s2-docs/pages/react-aria/frameworks.mdx @@ -22,6 +22,275 @@ export const description = 'How to integrate with your framework.'; Learn how to integrate React Aria with your framework. +## Client side routing + +Many React Aria components support rendering as HTML links. This section covers how to set up your app to integrate React Aria links with your framework or client side router. + +### Introduction + +React Aria components such as [Link](Link), [Menu](Menu), [Tabs](Tabs), [Table](Table), and many others support rendering elements as links that perform navigation when the user interacts with them. Each component that supports link behavior accepts the `href` prop, which causes the component to render an `` element. Other link DOM props such as `target` and `download` are also supported. + +Depending on the component, users may interact with links in different ways. For example, users can navigate between tabs using the arrow keys, or open a link in a ComboBox using the enter key. Because React Aria components accept the `href` prop rather than supporting arbitrary element overrides, they can ensure that link navigation occurs when it is appropriate for the component. + +By default, links perform native browser navigation when they are interacted with. However, many apps and frameworks use client side routers to avoid a full page reload when navigating between pages. The `RouterProvider` component configures all React Aria components within it to navigate using the client side router you provide. Set this up once in the root of your app, and any React Aria component with the `href` prop will automatically navigate using your router. + +Note that external links to different origins will not trigger client side routing, and will use native browser navigation. Additionally, if the link has a [target](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#target) other than `"_self"`, uses the [download](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#download) attribute, or the user presses modifier keys such as Command or Alt to change the default behavior, browser native navigation will occur instead of client side routing. + +### RouterProvider + +The `RouterProvider` component accepts two props: `navigate` and `useHref`. `navigate` should be set to a function received from your router for performing a client side navigation programmatically. `useHref` is an optional prop that converts a router-specific href to a native HTML href, e.g. prepending a base path. The following example shows the general pattern. Framework-specific examples are shown below. + +```tsx +import {RouterProvider} from 'react-aria-components'; +import {useNavigate, useHref} from 'your-router'; + +function App() { + let navigate = useNavigate(); + + return ( + + {/* ... */} + + ); +} +``` + +Note: if you are using React Aria hooks rather than components, you can import `RouterProvider` from `react-aria` instead. + +### Router options + +All React Aria link components accept a `routerOptions` prop, which is an object that is passed through to the client side router's `navigate` function as the second argument. This can be used to control any router-specific behaviors, such as scrolling, replacing instead of pushing to the history, etc. + +```tsx +{/* ...*/} +``` + +When using TypeScript, you can configure the `RouterConfig` type globally so that all link components have auto complete and type safety using a type provided by your router. + +```tsx +import type {RouterOptions} from 'your-router'; + +declare module 'react-aria-components' { + interface RouterConfig { + routerOptions: RouterOptions + } +} +``` + +### React Router + +The [useNavigate](https://reactrouter.com/en/main/hooks/use-navigate) hook from `react-router-dom` returns a `navigate` function you can pass to `RouterProvider`. The [useHref](https://reactrouter.com/en/main/hooks/use-href) hook can also be provided if you're using React Router's `basename` option. Ensure that the component that calls `useNavigate` and renders `RouterProvider` is inside the router component (e.g. `BrowserRouter`) so that it has access to React Router's internal context. The React Router `` element should also be defined inside React Aria's `` so that links inside the rendered routes have access to the router. + +```tsx +import {BrowserRouter, useNavigate, useHref, type NavigateOptions} from 'react-router-dom'; +import {RouterProvider} from 'react-aria-components'; + +declare module 'react-aria-components' { + interface RouterConfig { + routerOptions: NavigateOptions + } +} + +function App() { + let navigate = useNavigate(); + + return ( + + {/* Your app here... */} + + } /> + {/* ... */} + + + ); +} + + + + +``` + +### Next.js + +#### App router + +The [useRouter](https://nextjs.org/docs/app/api-reference/functions/use-router) hook from `next/navigation` returns a router object that can be used to perform navigation. `RouterProvider` should be rendered from a client component at the root of each page or layout that includes React Aria links. You can create a new client component for this, or combine it with other top-level providers as described in the [Next.js docs](https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#using-context-providers). + +```tsx +// app/provider.tsx +"use client"; + +import {useRouter} from 'next/navigation'; +import {RouterProvider} from 'react-aria-components'; + +declare module 'react-aria-components' { + interface RouterConfig { + routerOptions: NonNullable['push']>[1]> + } +} + +export function ClientProviders({children}) { + let router = useRouter(); + + return ( + + {children} + + ); +} +``` + +Then, in your page or layout server component, wrap your app in the `ClientProviders` component that you defined. + +```tsx +// app/layout.tsx +import {ClientProviders} from './provider'; + +export default function RootLayout({children}) { + return ( + + + {children} + + + ); +} +``` + +If you are using the Next.js [basePath](https://nextjs.org/docs/app/api-reference/next-config-js/basePath) setting, you'll need to configure an environment variable to access it. Then, provide a custom `useHref` function to prepend it to the href for all links. + +```tsx +// next.config.js +const basePath = '...'; +const nextConfig = { + basePath, + env: { + BASE_PATH: basePath + } +}; +``` + +```tsx +// app/provider.tsx +// ... + +export function ClientProviders({children}) { + let router = useRouter(); + /*- begin highlight -*/ + let useHref = (href: string) => process.env.BASE_PATH + href; + /*- end highlight -*/ + + return ( + + {children} + + ); +} +``` + +#### Pages router + +The [useRouter](https://nextjs.org/docs/pages/api-reference/functions/use-router) hook from `next/router` returns a router object that can be used to perform navigation. `RouterProvider` should be rendered at the root of each page that includes React Aria links, or in `pages/_app.tsx` to add it to all pages. + +```tsx +// pages/_app.tsx +import type {AppProps} from 'next/app'; +import {useRouter, type NextRouter} from 'next/router'; +import {RouterProvider} from 'react-aria-components'; + +declare module 'react-aria-components' { + interface RouterConfig { + routerOptions: NonNullable[2]> + } +} + +export default function MyApp({Component, pageProps}: AppProps) { + let router = useRouter(); + + return ( + router.push(href, undefined, opts)}> + + + ); +} +``` + +When using the [basePath](https://nextjs.org/docs/app/api-reference/next-config-js/basePath) configuration option, provide a `useHref` prop to `RouterProvider` to prepend it to links automatically. + +```tsx +// pages/_app.tsx +// ... + +export default function MyApp({Component, pageProps}: AppProps) { + let router = useRouter(); + + return ( + router.push(href, undefined, opts)} + /*- begin highlight -*/ + useHref={(href: string) => router.basePath + href} + /*- end highlight -*/ + > + + + ); +} +``` + +### Remix + +Remix uses React Router under the hood, so the same [useNavigate](https://reactrouter.com/en/main/hooks/use-navigate) and [useHref](https://reactrouter.com/en/main/hooks/use-href) hooks described above also work in Remix apps. `RouterProvider` should be rendered at the root of each page that includes React Aria links, or in `app/root.tsx` to add it to all pages. See the [Remix docs](https://remix.run/docs/en/main/file-conventions/root) for more details. + +```tsx +// app/root.tsx +import {useNavigate, useHref, Outlet} from '@remix-run/react'; +import type {NavigateOptions} from 'react-router-dom'; +import {RouterProvider} from 'react-aria-components'; + +declare module 'react-aria-components' { + interface RouterConfig { + routerOptions: NavigateOptions + } +} + +export default function App() { + let navigate = useNavigate(); + + return ( + + + {/* ... */} + + + + + + {/* ... */} + + + ); +} +``` + +### TanStack Router + +To use [TanStack Router](https://tanstack.com/router) with React Aria Components v1.11.0 or later, use the [createLink](https://tanstack.com/router/latest/docs/framework/react/guide/custom-link) function to wrap each React Aria component as a link. `RouterProvider` is not needed. + +```tsx +// src/Link.tsx +import {createLink} from '@tanstack/react-router'; +import {Link as ReactAriaLink, MenuItem} from 'react-aria-components'; + +export const Link = createLink(ReactAriaLink); +export const MenuItemLink = createLink(MenuItem); +``` + +In your app, use these components instead of importing directly from `react-aria-components`. + +## Locale and bundler setup + +To configure internationalization and optimize your bundle for your framework, follow the instructions for your framework or bundler below. + Next.jsReact RouterParcelVitewebpackRollupESBuild From 317dce0d9dc99a2f9da125b0a4c3e624f8a7548d Mon Sep 17 00:00:00 2001 From: Rob Hannay Date: Tue, 28 Apr 2026 14:57:01 +0000 Subject: [PATCH 2/3] =?UTF-8?q?docs:=20split=20client=20side=20routing=20s?= =?UTF-8?q?etup=20across=20framework=20tabs=20=E2=99=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the framework-specific RouterProvider setup into the existing Next.js, React Router, and a new TanStack Router tab in frameworks.mdx, rather than as one long section above all tabs. - Keep a brief 'Client side routing' intro above the tabs covering the general RouterProvider API and routerOptions. - Next.js tab: App Router (RouterProvider in client provider, plus optional basePath/useHref) and a 'Pages router' subsection. - React Router tab: framework-mode RouterProvider wired into the root layout, plus 'Declarative mode' and 'Remix' subsections. - New TanStack Router tab documents the createLink approach (RouterProvider not needed). - Bundler tabs (Parcel/Vite/webpack/Rollup/ESBuild) unchanged. Co-authored-by: Rook --- .../s2-docs/pages/react-aria/frameworks.mdx | 445 ++++++++---------- .../dev/s2-docs/src/icons/TanStackRouter.tsx | 9 + 2 files changed, 217 insertions(+), 237 deletions(-) create mode 100644 packages/dev/s2-docs/src/icons/TanStackRouter.tsx diff --git a/packages/dev/s2-docs/pages/react-aria/frameworks.mdx b/packages/dev/s2-docs/pages/react-aria/frameworks.mdx index 17c64672d99..13360093c80 100644 --- a/packages/dev/s2-docs/pages/react-aria/frameworks.mdx +++ b/packages/dev/s2-docs/pages/react-aria/frameworks.mdx @@ -8,6 +8,7 @@ import {Tabs, TabList, Tab, TabPanel, Text} from '@react-spectrum/s2'; import {StepList, Step, Counter} from '../../src/Step'; import Nextjs from '../../src/icons/Nextjs'; import ReactRouter from '../../src/icons/ReactRouter'; +import TanStackRouter from '../../src/icons/TanStackRouter'; import Vite from '../../src/icons/Vite'; import Parcel from '../../src/icons/Parcel'; import Webpack from '../../src/icons/Webpack'; @@ -24,21 +25,9 @@ export const description = 'How to integrate with your framework.'; ## Client side routing -Many React Aria components support rendering as HTML links. This section covers how to set up your app to integrate React Aria links with your framework or client side router. +Many React Aria components such as [Link](Link), [Menu](Menu), [Tabs](Tabs), and [Table](Table) support rendering as HTML links via the `href` prop. By default these perform native browser navigation, but you can integrate your client side router so that links navigate without a full page reload. -### Introduction - -React Aria components such as [Link](Link), [Menu](Menu), [Tabs](Tabs), [Table](Table), and many others support rendering elements as links that perform navigation when the user interacts with them. Each component that supports link behavior accepts the `href` prop, which causes the component to render an `` element. Other link DOM props such as `target` and `download` are also supported. - -Depending on the component, users may interact with links in different ways. For example, users can navigate between tabs using the arrow keys, or open a link in a ComboBox using the enter key. Because React Aria components accept the `href` prop rather than supporting arbitrary element overrides, they can ensure that link navigation occurs when it is appropriate for the component. - -By default, links perform native browser navigation when they are interacted with. However, many apps and frameworks use client side routers to avoid a full page reload when navigating between pages. The `RouterProvider` component configures all React Aria components within it to navigate using the client side router you provide. Set this up once in the root of your app, and any React Aria component with the `href` prop will automatically navigate using your router. - -Note that external links to different origins will not trigger client side routing, and will use native browser navigation. Additionally, if the link has a [target](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#target) other than `"_self"`, uses the [download](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#download) attribute, or the user presses modifier keys such as Command or Alt to change the default behavior, browser native navigation will occur instead of client side routing. - -### RouterProvider - -The `RouterProvider` component accepts two props: `navigate` and `useHref`. `navigate` should be set to a function received from your router for performing a client side navigation programmatically. `useHref` is an optional prop that converts a router-specific href to a native HTML href, e.g. prepending a base path. The following example shows the general pattern. Framework-specific examples are shown below. +The `RouterProvider` component configures all React Aria components within it to navigate using the router you provide. Set this up once at the root of your app, and any React Aria component with the `href` prop will automatically navigate using your router. ```tsx import {RouterProvider} from 'react-aria-components'; @@ -55,17 +44,19 @@ function App() { } ``` -Note: if you are using React Aria hooks rather than components, you can import `RouterProvider` from `react-aria` instead. +`navigate` should be a function received from your router for performing a client side navigation programmatically. `useHref` is an optional prop that converts a router-specific href to a native HTML href, e.g. prepending a base path. Note: if you are using React Aria hooks rather than components, you can import `RouterProvider` from `react-aria` instead. + +External links to different origins, links with a `target` other than `"_self"`, links using the `download` attribute, and clicks with modifier keys (e.g. Cmd/Alt) all fall back to native browser navigation. ### Router options -All React Aria link components accept a `routerOptions` prop, which is an object that is passed through to the client side router's `navigate` function as the second argument. This can be used to control any router-specific behaviors, such as scrolling, replacing instead of pushing to the history, etc. +All React Aria link components accept a `routerOptions` prop, which is passed through to the client side router's `navigate` function as the second argument. Use it to control router-specific behaviors, e.g. scrolling or replacing instead of pushing to the history. ```tsx {/* ...*/} ``` -When using TypeScript, you can configure the `RouterConfig` type globally so that all link components have auto complete and type safety using a type provided by your router. +When using TypeScript, configure the `RouterConfig` type globally so all link components have auto complete and type safety using a type provided by your router. ```tsx import type {RouterOptions} from 'your-router'; @@ -77,224 +68,12 @@ declare module 'react-aria-components' { } ``` -### React Router - -The [useNavigate](https://reactrouter.com/en/main/hooks/use-navigate) hook from `react-router-dom` returns a `navigate` function you can pass to `RouterProvider`. The [useHref](https://reactrouter.com/en/main/hooks/use-href) hook can also be provided if you're using React Router's `basename` option. Ensure that the component that calls `useNavigate` and renders `RouterProvider` is inside the router component (e.g. `BrowserRouter`) so that it has access to React Router's internal context. The React Router `` element should also be defined inside React Aria's `` so that links inside the rendered routes have access to the router. - -```tsx -import {BrowserRouter, useNavigate, useHref, type NavigateOptions} from 'react-router-dom'; -import {RouterProvider} from 'react-aria-components'; - -declare module 'react-aria-components' { - interface RouterConfig { - routerOptions: NavigateOptions - } -} - -function App() { - let navigate = useNavigate(); - - return ( - - {/* Your app here... */} - - } /> - {/* ... */} - - - ); -} - - - - -``` - -### Next.js - -#### App router - -The [useRouter](https://nextjs.org/docs/app/api-reference/functions/use-router) hook from `next/navigation` returns a router object that can be used to perform navigation. `RouterProvider` should be rendered from a client component at the root of each page or layout that includes React Aria links. You can create a new client component for this, or combine it with other top-level providers as described in the [Next.js docs](https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#using-context-providers). - -```tsx -// app/provider.tsx -"use client"; - -import {useRouter} from 'next/navigation'; -import {RouterProvider} from 'react-aria-components'; - -declare module 'react-aria-components' { - interface RouterConfig { - routerOptions: NonNullable['push']>[1]> - } -} - -export function ClientProviders({children}) { - let router = useRouter(); - - return ( - - {children} - - ); -} -``` - -Then, in your page or layout server component, wrap your app in the `ClientProviders` component that you defined. - -```tsx -// app/layout.tsx -import {ClientProviders} from './provider'; - -export default function RootLayout({children}) { - return ( - - - {children} - - - ); -} -``` - -If you are using the Next.js [basePath](https://nextjs.org/docs/app/api-reference/next-config-js/basePath) setting, you'll need to configure an environment variable to access it. Then, provide a custom `useHref` function to prepend it to the href for all links. - -```tsx -// next.config.js -const basePath = '...'; -const nextConfig = { - basePath, - env: { - BASE_PATH: basePath - } -}; -``` - -```tsx -// app/provider.tsx -// ... - -export function ClientProviders({children}) { - let router = useRouter(); - /*- begin highlight -*/ - let useHref = (href: string) => process.env.BASE_PATH + href; - /*- end highlight -*/ - - return ( - - {children} - - ); -} -``` - -#### Pages router - -The [useRouter](https://nextjs.org/docs/pages/api-reference/functions/use-router) hook from `next/router` returns a router object that can be used to perform navigation. `RouterProvider` should be rendered at the root of each page that includes React Aria links, or in `pages/_app.tsx` to add it to all pages. - -```tsx -// pages/_app.tsx -import type {AppProps} from 'next/app'; -import {useRouter, type NextRouter} from 'next/router'; -import {RouterProvider} from 'react-aria-components'; - -declare module 'react-aria-components' { - interface RouterConfig { - routerOptions: NonNullable[2]> - } -} - -export default function MyApp({Component, pageProps}: AppProps) { - let router = useRouter(); - - return ( - router.push(href, undefined, opts)}> - - - ); -} -``` - -When using the [basePath](https://nextjs.org/docs/app/api-reference/next-config-js/basePath) configuration option, provide a `useHref` prop to `RouterProvider` to prepend it to links automatically. - -```tsx -// pages/_app.tsx -// ... - -export default function MyApp({Component, pageProps}: AppProps) { - let router = useRouter(); - - return ( - router.push(href, undefined, opts)} - /*- begin highlight -*/ - useHref={(href: string) => router.basePath + href} - /*- end highlight -*/ - > - - - ); -} -``` - -### Remix - -Remix uses React Router under the hood, so the same [useNavigate](https://reactrouter.com/en/main/hooks/use-navigate) and [useHref](https://reactrouter.com/en/main/hooks/use-href) hooks described above also work in Remix apps. `RouterProvider` should be rendered at the root of each page that includes React Aria links, or in `app/root.tsx` to add it to all pages. See the [Remix docs](https://remix.run/docs/en/main/file-conventions/root) for more details. - -```tsx -// app/root.tsx -import {useNavigate, useHref, Outlet} from '@remix-run/react'; -import type {NavigateOptions} from 'react-router-dom'; -import {RouterProvider} from 'react-aria-components'; - -declare module 'react-aria-components' { - interface RouterConfig { - routerOptions: NavigateOptions - } -} - -export default function App() { - let navigate = useNavigate(); - - return ( - - - {/* ... */} - - - - - - {/* ... */} - - - ); -} -``` - -### TanStack Router - -To use [TanStack Router](https://tanstack.com/router) with React Aria Components v1.11.0 or later, use the [createLink](https://tanstack.com/router/latest/docs/framework/react/guide/custom-link) function to wrap each React Aria component as a link. `RouterProvider` is not needed. - -```tsx -// src/Link.tsx -import {createLink} from '@tanstack/react-router'; -import {Link as ReactAriaLink, MenuItem} from 'react-aria-components'; - -export const Link = createLink(ReactAriaLink); -export const MenuItemLink = createLink(MenuItem); -``` - -In your app, use these components instead of importing directly from `react-aria-components`. - -## Locale and bundler setup - -To configure internationalization and optimize your bundle for your framework, follow the instructions for your framework or bundler below. +Choose your framework or router below for setup instructions, including locale and bundler configuration. - Next.jsReact RouterParcelVitewebpackRollupESBuild + Next.jsReact RouterTanStack RouterParcelVitewebpackRollupESBuild - To integrate with Next.js (app router), ensure the locale on the server matches the client. + To integrate with Next.js (app router), ensure the locale on the server matches the client and configure `RouterProvider` so React Aria links use the Next.js router. @@ -325,18 +104,62 @@ To configure internationalization and optimize your bundle for your framework, f ``` - Create `app/provider.tsx`. This should render an `I18nProvider` to set the locale used by React Aria. + Create `app/provider.tsx`. This should render an `I18nProvider` to set the locale used by React Aria, and a `RouterProvider` so that React Aria components with `href` use the Next.js client side router. The [useRouter](https://nextjs.org/docs/app/api-reference/functions/use-router) hook from `next/navigation` returns a router object whose `push` function can be passed as `navigate`. ```tsx // app/provider.tsx "use client"; + import {useRouter} from 'next/navigation'; import {I18nProvider} from 'react-aria-components/I18nProvider'; + import {RouterProvider} from 'react-aria-components'; + + declare module 'react-aria-components' { + interface RouterConfig { + routerOptions: NonNullable['push']>[1]> + } + } + + export function ClientProviders({lang, children}) { + let router = useRouter(); + return ( + + + {children} + + + ); + } + ``` + + + If you are using the Next.js [basePath](https://nextjs.org/docs/app/api-reference/next-config-js/basePath) setting, expose it as an environment variable and provide a custom `useHref` function so React Aria prepends it to link hrefs. + + ```tsx + // next.config.js + const basePath = '...'; + const nextConfig = { + basePath, + env: { + BASE_PATH: basePath + } + }; + ``` + + ```tsx + // app/provider.tsx + // ... export function ClientProviders({lang, children}) { + let router = useRouter(); + /*- begin highlight -*/ + let useHref = (href: string) => process.env.BASE_PATH + href; + /*- end highlight -*/ return ( - {children} + + {children} + ); } @@ -346,9 +169,58 @@ To configure internationalization and optimize your bundle for your framework, f If you are using a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) (CSP) with a nonce, add a `` tag to your document head, setting the `content` attribute to the generated nonce value. React Aria automatically reads the nonce from this tag. + + ### Pages router + + If you're using the Next.js Pages router instead, render `RouterProvider` in `pages/_app.tsx`. The [useRouter](https://nextjs.org/docs/pages/api-reference/functions/use-router) hook from `next/router` returns a router object whose `push` function performs client side navigation. + + ```tsx + // pages/_app.tsx + import type {AppProps} from 'next/app'; + import {useRouter, type NextRouter} from 'next/router'; + import {RouterProvider} from 'react-aria-components'; + + declare module 'react-aria-components' { + interface RouterConfig { + routerOptions: NonNullable[2]> + } + } + + export default function MyApp({Component, pageProps}: AppProps) { + let router = useRouter(); + + return ( + router.push(href, undefined, opts)}> + + + ); + } + ``` + + When using the [basePath](https://nextjs.org/docs/app/api-reference/next-config-js/basePath) configuration option, provide a `useHref` prop so it's prepended to all links automatically. + + ```tsx + // pages/_app.tsx + // ... + + export default function MyApp({Component, pageProps}: AppProps) { + let router = useRouter(); + + return ( + router.push(href, undefined, opts)} + /*- begin highlight -*/ + useHref={(href: string) => router.basePath + href} + /*- end highlight -*/ + > + + + ); + } + ``` - To integrate with React Router (framework mode), ensure the locale on the server matches the client, and exclude localized strings from the client bundle. If you're using declarative mode, choose your bundler above. + To integrate with React Router (framework mode), ensure the locale on the server matches the client, and exclude localized strings from the client bundle. If you're using declarative mode, see the section below or choose your bundler tab. @@ -403,15 +275,28 @@ To configure internationalization and optimize your bundle for your framework, f ``` - In your root layout, set the `lang` and `dir` attributes on the `` element, and render a `RouterProvider` to configure React Aria links to use React Router. + In your root layout, set the `lang` and `dir` attributes on the `` element, and render a `RouterProvider` to configure React Aria links to use React Router. The [useNavigate](https://reactrouter.com/en/main/hooks/use-navigate) and [useHref](https://reactrouter.com/en/main/hooks/use-href) hooks come from `react-router`. ```tsx // app/root.tsx + /*- begin highlight -*/ + import {useNavigate, useHref, Outlet, type NavigateOptions} from 'react-router'; + import {RouterProvider} from 'react-aria-components'; + /*- end highlight -*/ import {useLocale} from 'react-aria-components/I18nProvider'; + /*- begin highlight -*/ + declare module 'react-aria-components' { + interface RouterConfig { + routerOptions: NavigateOptions + } + } + /*- end highlight -*/ + export function Layout({children}) { /*- begin highlight -*/ let {locale, direction} = useLocale(); + let navigate = useNavigate(); /*- end highlight -*/ return ( @@ -422,7 +307,11 @@ To configure internationalization and optimize your bundle for your framework, f {/* ... */} - {children} + {/*- begin highlight -*/} + + {children} + + {/*- end highlight -*/} {/* ... */} @@ -460,6 +349,88 @@ To configure internationalization and optimize your bundle for your framework, f If you are using a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) (CSP) with a nonce, add a `` tag to your document head, setting the `content` attribute to the generated nonce value. React Aria automatically reads the nonce from this tag. + + ### Declarative mode + + If you're using React Router in declarative mode (e.g. with `BrowserRouter`), render `RouterProvider` inside the router so it has access to React Router's context. The React Router `` element should be defined inside React Aria's `` so that links inside the rendered routes have access to the router. Then choose your bundler tab below for locale and CSP setup. + + ```tsx + import {BrowserRouter, Routes, Route, useNavigate, useHref, type NavigateOptions} from 'react-router-dom'; + import {RouterProvider} from 'react-aria-components'; + + declare module 'react-aria-components' { + interface RouterConfig { + routerOptions: NavigateOptions + } + } + + function App() { + let navigate = useNavigate(); + + return ( + + {/* Your app here... */} + + } /> + {/* ... */} + + + ); + } + + + + + ``` + + ### Remix + + Remix uses React Router under the hood, so the same `useNavigate` and `useHref` hooks work. Render `RouterProvider` in `app/root.tsx` to add it to all pages. + + ```tsx + // app/root.tsx + import {useNavigate, useHref, Outlet} from '@remix-run/react'; + import type {NavigateOptions} from 'react-router-dom'; + import {RouterProvider} from 'react-aria-components'; + + declare module 'react-aria-components' { + interface RouterConfig { + routerOptions: NavigateOptions + } + } + + export default function App() { + let navigate = useNavigate(); + + return ( + + + {/* ... */} + + + + + + {/* ... */} + + + ); + } + ``` + + + To use [TanStack Router](https://tanstack.com/router) with React Aria Components v1.11.0 or later, use the [createLink](https://tanstack.com/router/latest/docs/framework/react/guide/custom-link) function to wrap each React Aria component as a link. `RouterProvider` is not needed. + + ```tsx + // src/Link.tsx + import {createLink} from '@tanstack/react-router'; + import {Link as ReactAriaLink, MenuItem} from 'react-aria-components'; + + export const Link = createLink(ReactAriaLink); + export const MenuItemLink = createLink(MenuItem); + ``` + + In your app, use these wrapped components instead of importing directly from `react-aria-components`. For locale optimization and CSP setup, choose your bundler tab below. To integrate with a client-only Parcel SPA, and optimize the client bundle to include localized strings for your supported languages. diff --git a/packages/dev/s2-docs/src/icons/TanStackRouter.tsx b/packages/dev/s2-docs/src/icons/TanStackRouter.tsx new file mode 100644 index 00000000000..f8bacf235d7 --- /dev/null +++ b/packages/dev/s2-docs/src/icons/TanStackRouter.tsx @@ -0,0 +1,9 @@ +'use client'; + +import {createIcon} from '@react-spectrum/s2'; + +export default createIcon(props => ( + + + +)); From 995c22e0e9538e709f429876a758a626f1450e5e Mon Sep 17 00:00:00 2001 From: Rob Hannay Date: Wed, 29 Apr 2026 09:05:18 +0000 Subject: [PATCH 3/3] =?UTF-8?q?docs:=20explain=20client=20side=20routing?= =?UTF-8?q?=20via=20render=20prop=20instead=20of=20RouterProvider=20?= =?UTF-8?q?=E2=99=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the dead ./frameworks link on the Link docs page with a new 'Client side routing' section showing the render prop pattern for Next.js and React Router. Update getting-started.mdx to point to the Link docs for routing setup instead of the frameworks page. Revert previous changes to frameworks.mdx and remove TanStackRouter icon. Co-authored-by: Rook --- .../dev/s2-docs/pages/react-aria/Link.mdx | 26 +- .../s2-docs/pages/react-aria/frameworks.mdx | 254 +----------------- .../pages/react-aria/getting-started.mdx | 2 +- .../dev/s2-docs/src/icons/TanStackRouter.tsx | 9 - 4 files changed, 33 insertions(+), 258 deletions(-) delete mode 100644 packages/dev/s2-docs/src/icons/TanStackRouter.tsx diff --git a/packages/dev/s2-docs/pages/react-aria/Link.mdx b/packages/dev/s2-docs/pages/react-aria/Link.mdx index a569556b633..2388ff085e0 100644 --- a/packages/dev/s2-docs/pages/react-aria/Link.mdx +++ b/packages/dev/s2-docs/pages/react-aria/Link.mdx @@ -34,9 +34,33 @@ export const description = 'Allows a user to navigate to another page or resourc files={["starters/tailwind/src/Link.tsx"]} /> +## Client side routing + +By default, links with an `href` are handled by the browser as regular page navigations. To integrate with a client side router, use the `render` prop to delegate to your router's link component. This supports features like prefetching on hover and avoids full page reloads. + +```tsx +import {Link} from 'react-aria-components/Link'; +import NextLink from 'next/link'; + + }> + About + +``` + +```tsx +import {Link} from 'react-aria-components/Link'; +import {Link as RouterLink} from 'react-router'; + + }> + About + +``` + +See the [customization](customization#dom-elements) guide for more details on the `render` prop. + ## Events -Links with an `href` will be handled by the browser, or via a [client side router](./frameworks). Links without an `href` will be rendered as a `` instead of an ``. Use the `onPress` event to handle user interaction. +Links without an `href` will be rendered as a `` instead of an ``. Use the `onPress` event to handle user interaction. ```tsx render "use client"; diff --git a/packages/dev/s2-docs/pages/react-aria/frameworks.mdx b/packages/dev/s2-docs/pages/react-aria/frameworks.mdx index 13360093c80..04c1288126c 100644 --- a/packages/dev/s2-docs/pages/react-aria/frameworks.mdx +++ b/packages/dev/s2-docs/pages/react-aria/frameworks.mdx @@ -8,7 +8,6 @@ import {Tabs, TabList, Tab, TabPanel, Text} from '@react-spectrum/s2'; import {StepList, Step, Counter} from '../../src/Step'; import Nextjs from '../../src/icons/Nextjs'; import ReactRouter from '../../src/icons/ReactRouter'; -import TanStackRouter from '../../src/icons/TanStackRouter'; import Vite from '../../src/icons/Vite'; import Parcel from '../../src/icons/Parcel'; import Webpack from '../../src/icons/Webpack'; @@ -23,57 +22,10 @@ export const description = 'How to integrate with your framework.'; Learn how to integrate React Aria with your framework. -## Client side routing - -Many React Aria components such as [Link](Link), [Menu](Menu), [Tabs](Tabs), and [Table](Table) support rendering as HTML links via the `href` prop. By default these perform native browser navigation, but you can integrate your client side router so that links navigate without a full page reload. - -The `RouterProvider` component configures all React Aria components within it to navigate using the router you provide. Set this up once at the root of your app, and any React Aria component with the `href` prop will automatically navigate using your router. - -```tsx -import {RouterProvider} from 'react-aria-components'; -import {useNavigate, useHref} from 'your-router'; - -function App() { - let navigate = useNavigate(); - - return ( - - {/* ... */} - - ); -} -``` - -`navigate` should be a function received from your router for performing a client side navigation programmatically. `useHref` is an optional prop that converts a router-specific href to a native HTML href, e.g. prepending a base path. Note: if you are using React Aria hooks rather than components, you can import `RouterProvider` from `react-aria` instead. - -External links to different origins, links with a `target` other than `"_self"`, links using the `download` attribute, and clicks with modifier keys (e.g. Cmd/Alt) all fall back to native browser navigation. - -### Router options - -All React Aria link components accept a `routerOptions` prop, which is passed through to the client side router's `navigate` function as the second argument. Use it to control router-specific behaviors, e.g. scrolling or replacing instead of pushing to the history. - -```tsx -{/* ...*/} -``` - -When using TypeScript, configure the `RouterConfig` type globally so all link components have auto complete and type safety using a type provided by your router. - -```tsx -import type {RouterOptions} from 'your-router'; - -declare module 'react-aria-components' { - interface RouterConfig { - routerOptions: RouterOptions - } -} -``` - -Choose your framework or router below for setup instructions, including locale and bundler configuration. - - Next.jsReact RouterTanStack RouterParcelVitewebpackRollupESBuild + Next.jsReact RouterParcelVitewebpackRollupESBuild - To integrate with Next.js (app router), ensure the locale on the server matches the client and configure `RouterProvider` so React Aria links use the Next.js router. + To integrate with Next.js (app router), ensure the locale on the server matches the client. @@ -104,62 +56,18 @@ Choose your framework or router below for setup instructions, including locale a ``` - Create `app/provider.tsx`. This should render an `I18nProvider` to set the locale used by React Aria, and a `RouterProvider` so that React Aria components with `href` use the Next.js client side router. The [useRouter](https://nextjs.org/docs/app/api-reference/functions/use-router) hook from `next/navigation` returns a router object whose `push` function can be passed as `navigate`. + Create `app/provider.tsx`. This should render an `I18nProvider` to set the locale used by React Aria. ```tsx // app/provider.tsx "use client"; - import {useRouter} from 'next/navigation'; import {I18nProvider} from 'react-aria-components/I18nProvider'; - import {RouterProvider} from 'react-aria-components'; - - declare module 'react-aria-components' { - interface RouterConfig { - routerOptions: NonNullable['push']>[1]> - } - } export function ClientProviders({lang, children}) { - let router = useRouter(); return ( - - {children} - - - ); - } - ``` - - - If you are using the Next.js [basePath](https://nextjs.org/docs/app/api-reference/next-config-js/basePath) setting, expose it as an environment variable and provide a custom `useHref` function so React Aria prepends it to link hrefs. - - ```tsx - // next.config.js - const basePath = '...'; - const nextConfig = { - basePath, - env: { - BASE_PATH: basePath - } - }; - ``` - - ```tsx - // app/provider.tsx - // ... - - export function ClientProviders({lang, children}) { - let router = useRouter(); - /*- begin highlight -*/ - let useHref = (href: string) => process.env.BASE_PATH + href; - /*- end highlight -*/ - return ( - - - {children} - + {children} ); } @@ -169,58 +77,9 @@ Choose your framework or router below for setup instructions, including locale a If you are using a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) (CSP) with a nonce, add a `` tag to your document head, setting the `content` attribute to the generated nonce value. React Aria automatically reads the nonce from this tag. - - ### Pages router - - If you're using the Next.js Pages router instead, render `RouterProvider` in `pages/_app.tsx`. The [useRouter](https://nextjs.org/docs/pages/api-reference/functions/use-router) hook from `next/router` returns a router object whose `push` function performs client side navigation. - - ```tsx - // pages/_app.tsx - import type {AppProps} from 'next/app'; - import {useRouter, type NextRouter} from 'next/router'; - import {RouterProvider} from 'react-aria-components'; - - declare module 'react-aria-components' { - interface RouterConfig { - routerOptions: NonNullable[2]> - } - } - - export default function MyApp({Component, pageProps}: AppProps) { - let router = useRouter(); - - return ( - router.push(href, undefined, opts)}> - - - ); - } - ``` - - When using the [basePath](https://nextjs.org/docs/app/api-reference/next-config-js/basePath) configuration option, provide a `useHref` prop so it's prepended to all links automatically. - - ```tsx - // pages/_app.tsx - // ... - - export default function MyApp({Component, pageProps}: AppProps) { - let router = useRouter(); - - return ( - router.push(href, undefined, opts)} - /*- begin highlight -*/ - useHref={(href: string) => router.basePath + href} - /*- end highlight -*/ - > - - - ); - } - ``` - To integrate with React Router (framework mode), ensure the locale on the server matches the client, and exclude localized strings from the client bundle. If you're using declarative mode, see the section below or choose your bundler tab. + To integrate with React Router (framework mode), ensure the locale on the server matches the client, and exclude localized strings from the client bundle. If you're using declarative mode, choose your bundler above. @@ -275,28 +134,15 @@ Choose your framework or router below for setup instructions, including locale a ``` - In your root layout, set the `lang` and `dir` attributes on the `` element, and render a `RouterProvider` to configure React Aria links to use React Router. The [useNavigate](https://reactrouter.com/en/main/hooks/use-navigate) and [useHref](https://reactrouter.com/en/main/hooks/use-href) hooks come from `react-router`. + In your root layout, set the `lang` and `dir` attributes on the `` element, and render a `RouterProvider` to configure React Aria links to use React Router. ```tsx // app/root.tsx - /*- begin highlight -*/ - import {useNavigate, useHref, Outlet, type NavigateOptions} from 'react-router'; - import {RouterProvider} from 'react-aria-components'; - /*- end highlight -*/ import {useLocale} from 'react-aria-components/I18nProvider'; - /*- begin highlight -*/ - declare module 'react-aria-components' { - interface RouterConfig { - routerOptions: NavigateOptions - } - } - /*- end highlight -*/ - export function Layout({children}) { /*- begin highlight -*/ let {locale, direction} = useLocale(); - let navigate = useNavigate(); /*- end highlight -*/ return ( @@ -307,11 +153,7 @@ Choose your framework or router below for setup instructions, including locale a {/* ... */} - {/*- begin highlight -*/} - - {children} - - {/*- end highlight -*/} + {children} {/* ... */} @@ -349,88 +191,6 @@ Choose your framework or router below for setup instructions, including locale a If you are using a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) (CSP) with a nonce, add a `` tag to your document head, setting the `content` attribute to the generated nonce value. React Aria automatically reads the nonce from this tag. - - ### Declarative mode - - If you're using React Router in declarative mode (e.g. with `BrowserRouter`), render `RouterProvider` inside the router so it has access to React Router's context. The React Router `` element should be defined inside React Aria's `` so that links inside the rendered routes have access to the router. Then choose your bundler tab below for locale and CSP setup. - - ```tsx - import {BrowserRouter, Routes, Route, useNavigate, useHref, type NavigateOptions} from 'react-router-dom'; - import {RouterProvider} from 'react-aria-components'; - - declare module 'react-aria-components' { - interface RouterConfig { - routerOptions: NavigateOptions - } - } - - function App() { - let navigate = useNavigate(); - - return ( - - {/* Your app here... */} - - } /> - {/* ... */} - - - ); - } - - - - - ``` - - ### Remix - - Remix uses React Router under the hood, so the same `useNavigate` and `useHref` hooks work. Render `RouterProvider` in `app/root.tsx` to add it to all pages. - - ```tsx - // app/root.tsx - import {useNavigate, useHref, Outlet} from '@remix-run/react'; - import type {NavigateOptions} from 'react-router-dom'; - import {RouterProvider} from 'react-aria-components'; - - declare module 'react-aria-components' { - interface RouterConfig { - routerOptions: NavigateOptions - } - } - - export default function App() { - let navigate = useNavigate(); - - return ( - - - {/* ... */} - - - - - - {/* ... */} - - - ); - } - ``` - - - To use [TanStack Router](https://tanstack.com/router) with React Aria Components v1.11.0 or later, use the [createLink](https://tanstack.com/router/latest/docs/framework/react/guide/custom-link) function to wrap each React Aria component as a link. `RouterProvider` is not needed. - - ```tsx - // src/Link.tsx - import {createLink} from '@tanstack/react-router'; - import {Link as ReactAriaLink, MenuItem} from 'react-aria-components'; - - export const Link = createLink(ReactAriaLink); - export const MenuItemLink = createLink(MenuItem); - ``` - - In your app, use these wrapped components instead of importing directly from `react-aria-components`. For locale optimization and CSP setup, choose your bundler tab below. To integrate with a client-only Parcel SPA, and optimize the client bundle to include localized strings for your supported languages. diff --git a/packages/dev/s2-docs/pages/react-aria/getting-started.mdx b/packages/dev/s2-docs/pages/react-aria/getting-started.mdx index 6663fe9a542..843cb930a01 100644 --- a/packages/dev/s2-docs/pages/react-aria/getting-started.mdx +++ b/packages/dev/s2-docs/pages/react-aria/getting-started.mdx @@ -185,4 +185,4 @@ In this tutorial, we'll build a custom [Select](Select) component. ## Framework setup -React Aria works out of the box in any React framework. When you're ready, follow our [framework setup](frameworks) guide to optimize the bundle size, configure internationalization, and integrate with client side routers. +React Aria works out of the box in any React framework. When you're ready, follow our [framework setup](frameworks) guide to optimize the bundle size and configure internationalization. To integrate with a client side router, use the `render` prop as described in the [Link](Link) docs. diff --git a/packages/dev/s2-docs/src/icons/TanStackRouter.tsx b/packages/dev/s2-docs/src/icons/TanStackRouter.tsx deleted file mode 100644 index f8bacf235d7..00000000000 --- a/packages/dev/s2-docs/src/icons/TanStackRouter.tsx +++ /dev/null @@ -1,9 +0,0 @@ -'use client'; - -import {createIcon} from '@react-spectrum/s2'; - -export default createIcon(props => ( - - - -));