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 --appcd my-appInstall 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/layoutYou 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/postcssConfigure PostCSS
Create or update your PostCSS config at the project root.
// postcss.config.mjsexport 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.tsxexport 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.