Skip to main content

Next.js Setup

Step-by-step guide to set up Ninna UI in a Next.js 15 project with the App Router and Tailwind CSS v4. Best choice for server-rendered applications.

Prerequisites

  • Node.js 18+
  • Next.js 15 with App Router
  • Tailwind CSS v4

Create Project

Skip this step if you already have a Next.js project.

npx create-next-app@latest my-app --typescript --tailwind --app
cd my-app

Install Ninna UI

Install the component packages you need. All packages auto-install @ninna-ui/core.

pnpm add @ninna-ui/primitives @ninna-ui/feedback @ninna-ui/forms @ninna-ui/layout

You can also install individual packages later - e.g. @ninna-ui/overlays, @ninna-ui/navigation, @ninna-ui/data-display.

Install Tailwind CSS

Next.js uses the @tailwindcss/postcss plugin for Tailwind integration.

pnpm add
pnpm add -D tailwindcss @tailwindcss/postcss

Configure PostCSS

Create or update your PostCSS config at the project root.

// postcss.config.mjs
export default {
plugins: {
"@tailwindcss/postcss": {},
},
};

CSS Setup

Replace the contents of your global CSS file.

In app/globals.css:

@import "tailwindcss";
@import "@ninna-ui/core/theme/presets/default.css";
@variant dark (&:is(.dark *));

Then add data-theme to your root layout:

// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" className="light" data-theme="default" suppressHydrationWarning>
<head></head>
<body className="min-h-screen bg-base-50 text-base-content antialiased" suppressHydrationWarning>
{children}
</body>
</html>
);
}

The theme preset automatically includes all utility classes used by Ninna UI components - no @source directive needed. Note: the updated approach uses suppressHydrationWarning and className="light" to prevent SSR hydration mismatches.

Your First Component

Verify the setup by rendering a Ninna UI component.

"use client";
import { Button, Heading, Text } from "@ninna-ui/primitives";
export default function Page() {
return (
<div className="p-8">
<Heading as="h1" size="3xl">Hello Ninna UI</Heading>
<Text className="text-base-content/70 mt-2">It works!</Text>
<Button color="primary" className="mt-4">Click me</Button>
</div>
);
}

"use client" Directive

Important: Ninna UI components work in Server Components by default.

Ninna UI components work in Server Components out of the box - no "use client" directive needed. Only add "use client" when your component uses React hooks like useState or useEffect.

You can freely use Ninna UI components in Server Components and only mark the specific components that need client-side state as client components.

SSR Ready: All Ninna UI components are fully SSR compatible and work in React Server Components without any additional configuration.

// app/components/my-form.tsx
// Only add "use client" if you need hooks like useState
"use client";
import { Button, Input, Field } from "@ninna-ui/forms";
export function MyForm() {
const [value, setValue] = useState(""); // Hook requires "use client"
return (
<Field label="Name">
<Input value={value} onChange={(e) => setValue(e.target.value)} />
<Button>Submit</Button>
</Field>
);
}

Theme Presets

Switch themes by changing the CSS import and the data-theme attribute.

/* 1. Change the CSS import in globals.css */
/* Default - Electric purple + magenta */
@import "@ninna-ui/core/theme/presets/default.css";
/* Ocean - Blue + cyan */
@import "@ninna-ui/core/theme/presets/ocean.css";
/* Sunset - Orange + rose */
@import "@ninna-ui/core/theme/presets/sunset.css";
/* Forest - Green + amber */
@import "@ninna-ui/core/theme/presets/forest.css";
/* Minimal - Monochrome */
@import "@ninna-ui/core/theme/presets/minimal.css";
/* 2. Update data-theme in app/layout.tsx */
/* <html lang="en" data-theme="ocean"> */

Dark mode works automatically via prefers-color-scheme or by adding the .dark class to <html>. The data-theme attribute is optional for zero-config setup, but required for per-section theming or switching presets.