Skip to main content

Next.js Setup

Primus UI works with both the Next.js App Router (Next.js 13+) and Pages Router. Because Primus components use React hooks and browser APIs, they must run as Client Components.

Install​

npm install primus-react-ui @primus/ui-core

Import styles​

In your root layout (App Router) or _app.tsx (Pages Router):

// app/layout.tsx
import '@primus/ui-core/dist/primus-ui.min.css';
import 'primus-react-ui/styles.css';
import { PrimusThemeProvider, PrimusUiCoreBridge } from 'primus-react-ui';

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<PrimusThemeProvider defaultTheme="dark">
<PrimusUiCoreBridge />
{children}
</PrimusThemeProvider>
</body>
</html>
);
}

Mark components as Client Components​

Primus SDK components use hooks internally. Any file that imports from primus-react-ui must have 'use client' at the top.

// app/dashboard/page.tsx — Server Component (fine, no Primus imports)
import { DashboardClient } from './dashboard-client';

export default function DashboardPage() {
return <DashboardClient />;
}
// app/dashboard/dashboard-client.tsx — Client Component
'use client';

import { PrimusStatCard, PrimusDataTable } from 'primus-react-ui';
import { useState, useEffect } from 'react';

export function DashboardClient() {
const [stats, setStats] = useState(null);

useEffect(() => {
fetch('/api/stats').then(r => r.json()).then(setStats);
}, []);

return (
<div>
<PrimusStatCard title="Revenue" value={stats?.revenue ?? '—'} />
<PrimusDataTable columns={cols} data={stats?.rows ?? []} rowKey="id" />
</div>
);
}
Rule of thumb

Create a *-client.tsx wrapper for any page that uses Primus components. Keep data fetching in the Server Component above it.

next.config.js — transpilePackages​

If you see module resolution errors, add primus-react-ui to transpilePackages:

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
transpilePackages: ['primus-react-ui'],
};

module.exports = nextConfig;

Auth with Next.js​

Use PrimusProvider in the root layout for auth wiring:

// app/layout.tsx
'use client';

import { PrimusProvider, PrimusThemeProvider, PrimusUiCoreBridge } from 'primus-react-ui';
import '@primus/ui-core/dist/primus-ui.min.css';

export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<PrimusProvider
authority="https://api.yourdomain.com"
authBasePath="/api/auth"
clientId="my-app">
<PrimusThemeProvider defaultTheme="dark">
<PrimusUiCoreBridge />
{children}
</PrimusThemeProvider>
</PrimusProvider>
</body>
</html>
);
}

Protecting routes (App Router)​

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(req: NextRequest) {
const token = req.cookies.get('primus_token')?.value;
if (!token && req.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', req.url));
}
}

export const config = { matcher: ['/dashboard/:path*'] };

Common issues​

ErrorFix
window is not definedAdd 'use client' to the file importing from primus-react-ui
useContext / hook errors in Server ComponentSame fix — add 'use client'
CSS not loading in productionEnsure primus-react-ui is in transpilePackages in next.config.js
Flash of unstyled contentImport CSS in layout.tsx before any component rendering