mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
* chore(deps): sync with RA release * fix(tabs): duplicate onClick * chore(docs): update tanstack content * chore(docs): set updated flag * chore(docs): update meta
326 lines
8.7 KiB
Plaintext
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).
|