Astro Setup
Step-by-step guide to set up Ninna UI in an Astro 5 project with React integration and Tailwind CSS v4. Use Ninna UI's React components inside Astro's island architecture.
Prerequisites
- Node.js 18+
- Astro 5
@astrojs/reactintegration- Tailwind CSS v4 via
@tailwindcss/vite
Create Project
Skip this step if you already have an Astro project.
npm create astro@latest my-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/layout @astrojs/reactYou can also install additional packages later — e.g. @ninna-ui/overlays, @ninna-ui/navigation, @ninna-ui/data-display.
Install Tailwind CSS
Astro uses Vite under the hood — use the @tailwindcss/vite plugin for the fastest builds.
pnpm add pnpm add -D tailwindcss @tailwindcss/viteConfigure Astro
Add the React integration and Tailwind CSS plugin to your Astro config.
// astro.config.mjsimport { defineConfig } from 'astro/config';import react from '@astrojs/react';import tailwindcss from '@tailwindcss/vite';
export default defineConfig({ integrations: [react()], vite: { plugins: [tailwindcss()], },});CSS Setup
Create your global styles file.
Create src/styles/globals.css:
@import "tailwindcss";@import "@ninna-ui/core/theme/presets/default.css";
/* Enable dark mode support */@variant dark (&:is(.dark *));Layout Setup
Create a base layout that imports your styles and sets the data-theme attribute.
---// src/layouts/Layout.astroimport "../styles/globals.css";
interface Props { title: string;}const { title } = Astro.props;---<!doctype html><html lang="en" data-theme="default"> <head> <meta charset="UTF-8" /> <meta name="description" content="My Ninna UI + Astro app" /> <meta name="viewport" content="width=device-width" /> <title>{title}</title> </head> <body class="min-h-screen bg-base-50 text-base-content antialiased"> <slot /> </body></html>The data-theme attribute must match the preset name from your CSS import.
Your First Component
Create a React component and use it in an Astro page.
React components must be rendered with a client: directive to be interactive:
// src/components/Hero.tsximport { Button, Heading, Text } from "@ninna-ui/primitives";
export function Hero() { return ( <div className="p-8 text-center"> <Heading as="h1" size="3xl">Hello Ninna UI + Astro</Heading> <Text className="text-base-content/70 mt-2">It works!</Text> <Button color="primary" className="mt-4">Get Started</Button> </div> );}---// src/pages/index.astroimport Layout from '../layouts/Layout.astro';import { Hero } from '../components/Hero';---<Layout title="My App"> <Hero client:load /></Layout>Use client:load for interactive components, or client:idle / client:visible for deferred hydration.
Vite Version Note
Astro 5 requires Vite 7. Pin the version to avoid warnings.
Add overrides to your package.json to ensure Vite 7 is used across all package managers:
{ "overrides": { "vite": "^7.0.0" }, "resolutions": { "vite": "^7.0.0" }, "pnpm": { "overrides": { "vite": "^7.0.0" } }}Theme Presets
Switch themes by changing the CSS import and the data-theme attribute.
/* 1. Change the CSS import in src/styles/globals.css */@import "@ninna-ui/core/theme/presets/default.css"; /* Electric purple */@import "@ninna-ui/core/theme/presets/ocean.css"; /* Blue + cyan */@import "@ninna-ui/core/theme/presets/sunset.css"; /* Orange + rose */@import "@ninna-ui/core/theme/presets/forest.css"; /* Green + amber */@import "@ninna-ui/core/theme/presets/minimal.css"; /* Monochrome */
/* 2. Update data-theme in src/layouts/Layout.astro *//* <html lang="en" data-theme="ocean"> */Dark mode works automatically via prefers-color-scheme or by adding the .dark class to <html>.