WK 36eb421c66
chore(deps): bump RA dependencies (#5517)
* chore(deps): sync with RA release

* fix(tabs): duplicate onClick

* chore(docs): update tanstack content

* chore(docs): set updated flag

* chore(docs): update meta
2025-07-29 00:51:47 +08:00

326 lines
8.7 KiB
Plaintext

---
title: Routing
description: Learn how to integrate client side routing into your HeroUI application.
---
# Routing
HeroUI Components such as [Tabs](/docs/components/tabs), [Listbox](/docs/components/listbox), [Dropdown](/docs/components/dropdown) and many others offer
the flexibility to be rendered as **HTML links**.
<CarbonAd />
## Introduction
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 `HeroUIProvider` component configures all HeroUI components within it to navigate using the client side
router you provide.
Set this up once in the `root` of your app, and any HeroUI component with the `href` prop will automatically navigate
using your router.
## HeroUIProvider Setup
The `HeroUIProvider` component accepts `navigate` and `useHref` props. `navigate` is a router function for client-side
navigation, while `useHref` optionally converts router hrefs to native HTML hrefs. Here's the pattern:
```jsx
import * as React from "react";
import {HeroUIProvider} from "@heroui/react";
import {useNavigate, useHref} from "your-router";
function App() {
const navigate = useNavigate();
return (
<HeroUIProvider navigate={navigate} useHref={useHref}>
<YourApplication />
</HeroUIProvider>
);
}
```
<Spacer y={2} />
> **Note**: Framework-specific examples are shown below.
### Router Options
All `HeroUI` link components accept a `routerOptions` prop that passes options to the router's navigate function for
controlling behavior like scrolling and history navigation.
```jsx
<DropdownItem href="/login" routerOptions={{replace: true}}>
{/* ...*/}
</DropdownItem>
```
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-types/shared" {
interface RouterConfig {
routerOptions: RouterOptions;
}
}
```
<Spacer y={2} />
## Next.js
#### App Router
Go to your `app/providers.tsx` or `app/providers.jsx` (create it if it doesn't exist) and add the
`useRouter` hook from `next/navigation`, it returns a router object that can be used to perform navigation.
> Check the [Next.js docs](https://nextjs.org/docs/app/api-reference/functions/use-router) for more details.
<Steps>
#### Add the `useRouter`
```tsx {15}
// app/providers.tsx
"use client";
import {useRouter} from "next/navigation";
import {HeroUIProvider} from "@heroui/react";
// Only if using TypeScript
declare module "@react-types/shared" {
interface RouterConfig {
routerOptions: NonNullable<Parameters<ReturnType<typeof useRouter>["push"]>[1]>;
}
}
export function Providers({children}: {children: React.ReactNode}) {
const router = useRouter();
return <HeroUIProvider navigate={router.push}>{children}</HeroUIProvider>;
}
```
#### Add Provider to Root
Now, Go to your `root` layout page and wrap it with the `HeroUIProvider`:
```tsx {8}
// app/layout.tsx
import {Providers} from "./providers";
export default function RootLayout({children}: {children: React.ReactNode}) {
return (
<html lang="en" className="dark">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
```
> **Note**: Skip this step if you already set up the `HeroUIProvider` in your app.
#### Next.js Base Path (Optional)
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.
```js
// next.config.js
const basePath = "...";
const nextConfig = {
basePath,
env: {
BASE_PATH: basePath,
},
};
```
Then, provide a custom `useHref` function to prepend it to the href for all links.
```tsx {9,12}
// app/providers.tsx
"use client";
import {useRouter} from "next/navigation";
import {HeroUIProvider} from "@heroui/react";
export function Providers({children}: {children: React.ReactNode}) {
const router = useRouter();
const useHref = (href: string) => process.env.BASE_PATH + href;
return (
<HeroUIProvider navigate={router.push} useHref={useHref}>
{children}
</HeroUIProvider>
);
}
```
</Steps>
### Pages Router
Go to pages`/_app.js` or `pages/_app.tsx` (create it if it doesn't exist) and add the`useRouter` hook
from `next/router`, it returns a router object that can be used to perform navigation.
```tsx
// pages/_app.tsx
import type {AppProps} from "next/app";
import {type NextRouter, useRouter} from "next/router";
import {HeroUIProvider} from "@heroui/react";
declare module "@react-types/shared" {
interface RouterConfig {
routerOptions: NonNullable<
Parameters<NextRouter['push']>[2]
>;
}
}
function MyApp({Component, pageProps}: AppProps) {
const router = useRouter();
return (
<HeroUIProvider navigate={router.push}>
<Component {...pageProps} />
</HeroUIProvider>
);
}
export default MyApp;
```
When using the [basePath](https://nextjs.org/docs/app/api-reference/next-config-js/basePath) configuration option,
provide a `useHref` option to the router passed to Provider to prepend it to links automatically.
```tsx {8}
// pages/_app.tsx
import type {AppProps} from "next/app";
import {HeroUIProvider} from "@heroui/react";
import {useRouter} from "next/router";
function MyApp({Component, pageProps}: AppProps) {
const router = useRouter();
const useHref = (href: string) => router.basePath + href;
return (
<HeroUIProvider navigate={router.push} useHref={useHref}>
<Component {...pageProps} />
</HeroUIProvider>
);
}
export default MyApp;
```
## React Router
Use the `useNavigate` hook from `react-router-dom` to get the `navigate` function for routing. The `useHref` hook can be used with React Router's `basename` option.
Make sure to place the component using these hooks inside `BrowserRouter` and keep `<Routes>` within `HeroUIProvider`. Here's how to set it up in your App component:
```tsx
// App.tsx or App.jsx
import type {NavigateOptions} from "react-router-dom";
import {BrowserRouter, useNavigate, useHref} from "react-router-dom";
import {HeroUIProvider} from "@heroui/react";
declare module "@react-types/shared" {
interface RouterConfig {
routerOptions: NavigateOptions;
}
}
function App() {
const navigate = useNavigate();
return (
<HeroUIProvider navigate={navigate} useHref={useHref}>
{/* Your app here... */}
<Routes>
<Route path="/" element={<HomePage />} />
{/* ... */}
</Routes>
</HeroUIProvider>
);
}
// main.tsx or main.jsx
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
);
```
Ensure that the component that calls `useNavigate` and renders `HeroUIProvider` is inside the router
component (e.g. `BrowserRouter`) so that it has access to React Router's internal context. The React Router `<Routes>`
element should also be defined inside `HeroUIProvider` so that links inside the rendered routes have access
to the router.
## Remix
Remix uses React Router under the hood, so the same `useNavigate` and `useHref` hook described above also works in Remix
apps. `HeroUIProvider` should be rendered at the `root` of each page that includes HeroUI components, 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 type {NavigateOptions} from 'react-router-dom';
import {useNavigate, useHref, Outlet} from "@remix-run/react";
import {HeroUIProvider} from "@heroui/react";
declare module "@react-types/shared" {
interface RouterConfig {
routerOptions: NavigateOptions;
}
}
export default function App() {
const navigate = useNavigate();
return (
<html lang="en">
<head>{/* ... */}</head>
<body>
<HeroUIProvider navigate={navigate} useHref={useHref}>
<Outlet />
</HeroUIProvider>
{/* ... */}
</body>
</html>
);
}
```
## TanStack
To use [TanStack Router](https://tanstack.com/router/latest), use the [createLink](https://tanstack.com/router/latest/docs/framework/react/guide/custom-link) function to wrap each HeroUI component as a link. `RouterProvider` is not needed.
```tsx
// app/root.tsx
import {createLink} from '@tanstack/react-router';
import {Link as HeroUILink, DropdownItem} from '@heroui/react';
export const Link = createLink(HeroUILink);
export const DropdownItemLink = createLink(DropdownItem);
```
<Spacer y={2} />
> For more information about routing in React Aria, visit the [React Aria Routing Guide](https://react-spectrum.adobe.com/react-aria/routing.html).