Next.Js
Learn how to integrate React Aria in Next.Js
Create Project
Run the init command to create a new Next.js project or to setup an existing one:
or you can choose any theme listed here
Add components
You can now start adding components to your project.
Client Providers
To integrate with Next.js (app router), ensure the locale on the server matches the client, and configure React Aria links to use the Next.js router.
"use client"
import { useRouter } from 'next/navigation'
import { RouterProvider, I18nProvider } from 'react-aria-components'
// Configure the type of the `routerOptions` prop on all React Aria components.
declare module 'react-aria-components' {
interface RouterConfig {
routerOptions: NonNullable<Parameters<ReturnType<typeof useRouter>['push']>[1]>
}
}
export function ClientProviders({lang, children}) {
const router = useRouter()
return (
<I18nProvider locale={lang}>
<RouterProvider navigate={router.push}>
{children}
</RouterProvider>
</I18nProvider>
)
}Then use in your root layout
import { headers } from 'next/headers'
import { isRTL } from 'react-aria-components'
import { ClientProviders } from '@/components/client-provider'
export default async function RootLayout({children}) {
// Get the user's preferred language from the Accept-Language header.
// You could also get this from a database, URL param, etc.
const acceptLanguage = (await headers()).get('accept-language')
const lang = acceptLanguage?.split(/[,;]/)[0] || 'en-US'
return (
<html lang={lang} dir={isRTL(lang) ? 'rtl' : 'ltr'} suppressHydrationWarning>
<body>
<ClientProviders lang={lang}>
{children}
</ClientProviders>
</body>
</html>
)
}Dark Mode
You may use next-themes to implement dark mode in Next.Js
Theme Provider
"use client"
import { ThemeProvider as NextThemesProvider, type ThemeProviderProps, useTheme } from "next-themes"
const ThemeProvider = ({ children, ...props }: ThemeProviderProps) => {
return (
<NextThemesProvider enableSystem storageKey="hq-theme" {...props}>
{children}
</NextThemesProvider>
)
}
export { ThemeProvider, useTheme }Then use in your root layout
import { ClientProviders } from '@/components/client-provider'
import { ThemeProvider } from '@/components/theme-provider'
...
<html lang={lang} dir={isRTL(lang) ? 'rtl' : 'ltr'} suppressHydrationWarning>
<body>
<ClientProviders lang={lang}>
<ThemeProvider attribute='class'>
{children}
</ThemeProvider>
</ClientProviders>
</body>
</html>
...Theme Switcher
'use client'
import { useTheme } from '@/components/theme-provider'
import { IconMoon, IconSun } from '@tabler/icons-react'
import { Button } from '@/components/ui/button'
export function ThemeSwitcher({ variant = 'outline' }: { variant?: 'outline' | 'ghost' }) {
const { resolvedTheme, setTheme } = useTheme()
return (
<Button
aria-label={`Switch to ${resolvedTheme}` === 'light' ? 'dark' : 'light' + 'mode'}
onPress={() => setTheme(resolvedTheme === 'light' ? 'dark' : 'light')}
size='icon'
variant={variant}
>
<IconSun aria-hidden className='rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0' />
<IconMoon aria-hidden className='absolute rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100' />
</Button>
)
}