HQ UI

Next.Js

Learn how to integrate HQ UI in Next.Js (App Router)

Create New Project

Run the init command to create a new Next.js project or to setup an existing one:

npx shadcn@latest init https://hq-ui.vercel.app/r/default

Registry

First, add the HQ UI in your components.json:

components.json
  ...
  "registries": {
    "@hq": "https://hq-ui.vercel.app/r/{name}"
  }

Add Components

You can now start adding components to your project.

npx shadcn@latest add @hq/button

Or if you don't wan't to modify components.json, you can use this command

npx shadcn@latest add https://hq-ui.vercel.app/r/button

Client Side Routing

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.

Client Provider

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.

client-provider.tsx
"use client"

import { useRouter } from 'next/navigation'
import { RouterProvider } from 'react-aria-components'

declare module 'react-aria-components' {
  interface RouterConfig {
    routerOptions: NonNullable<Parameters<ReturnType<typeof useRouter>['push']>[1]>
  }
}

export function ClientProviders({ children }: { children: React.ReactNode }) {
  const router = useRouter()

  return (
    <RouterProvider navigate={router.push}>
      {children}
    </RouterProvider>
  )
}

Then use in your root layout

app/layout.tsx
import { Geist, Geist_Mono } from "next/font/google"

import "./globals.css"
import { ThemeProvider } from "@/components/theme-provider"
import { ClientProvider } from '@/components/client-provider'

const fontSans = Geist({
  subsets: ["latin"],
  variable: "--font-sans",
})

const fontMono = Geist_Mono({
  subsets: ["latin"],
  variable: "--font-mono",
})


export default async function RootLayout({
  children
}: Readonly<{
  children: React.ReactNode
}>){
  return (
    <html
      lang='en'
      suppressHydrationWarning
      className={`${fontSans.variable} ${fontMono.variable} font-sans antialiased`}
    >
      <body>
        <ThemeProvider>
          <ClientProvider>
            {children}
          </ClientProvider>
        </ThemeProvider>
      </body>
    </html>
  )
}

Dark Mode

Theme Provider

If you are using the New Shadcn CLI, Theme Provider is already added. You can skip this step

Theme Switcher

components/theme-switcher.tsx
'use client'

import { useTheme } from 'next-themes'
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>
  )
}