UI components, fully yours.
NexUI is a collection of hand-crafted, accessible components built with pure Tailwind CSS and React — inspired by the shadcn/ui copy-paste philosophy. Copy the code and own every pixel.
# 1. Initialize (once per project)
$ pnpm dlx @jessin/nexui@latest init
Writing nexui.config.ts
Writing lib/utils.ts
Updating globals.css
# 2. Add any component
$ pnpm dlx @jessin/nexui@latest add button card badge
Writing components/ui/button.tsx
Writing components/ui/card.tsx
Writing components/ui/badge.tsx
# 3. Import and use — it's just your code
import { Button } from "@/components/ui/button"Inspired by shadcn/ui
Built in the same spirit as shadcn/ui — copy-paste ownership, zero hidden wrappers. Pure HTML, Tailwind CSS, and React state you can read and modify.
No npm install
Nothing to install or configure. Browse a component, copy the code, paste it into your project. That is the full workflow.
You own the code
The output is plain TypeScript and Tailwind. Rename it, restyle it, refactor it — there are no hidden layers between you and the UI.
Component Showcase
Everything you need.
Hand-crafted, accessible components inspired by the shadcn/ui copy-paste philosophy. Drop any component straight into your project and own every line.

“The best components library we've ever used.”
— Alex Chen, Product Designer
Sign-in, sign-up, and multi-step account creation flows with OAuth, password strength validation, and 2FA.
Explore all components
50+ components across Auth, Chat, Data Views, Charts, Forms, Carousel, and more.
Installation
Up and running in minutes.
Inspired by the shadcn/ui copy-paste model — no package to install, no version conflicts. Initialize once, then add exactly the components you need.
Framework support
Next.js
App Router + Pages Router
Vite + React
Works out of the box
Remix
Use with Tailwind preset
Astro
React islands
React Router v7
Framework mode
TanStack Start
Community tested
01. Create your project
Start with a Next.js or Vite project. NexUI works with any React framework — no special setup required beyond Tailwind CSS.
Note — Already have a project? Skip straight to step 2.
CLI
One command away.
The NexUI CLI initializes your project and pulls any component straight into your codebase. No registries, no runtime, no wrappers.
Config file
// nexui.config.ts
import type { NexUIConfig } from "@jessin/nexui"
export default {
// Directory where component files are written
outputDir: "components/ui",
// Path to your cn() utility
utils: "lib/utils.ts",
// Component style variant: "minimal" | "rounded" | "sharp"
style: "minimal",
// Write TypeScript (.tsx) or JavaScript (.jsx)
typescript: true,
} satisfies NexUIConfignexui init
Scaffolds nexui.config.ts, writes the cn utility to lib/utils.ts, and injects CSS variables into globals.css. Run once per project.
Tip — Run npx @jessin/nexui@latest add with no arguments to open an interactive component picker in your terminal.
CLI vs manual copy-paste
Theming
Make it yours.
All components use CSS custom properties — no theming library, no provider, no context. Swap your accent color, tweak the radius, and the entire system updates instantly.
Preset themes
CSS variables — one file, full control
:root {
--background: oklch(0.09 0 0);
--foreground: oklch(0.96 0 0);
--primary: oklch(0.65 0.17 160); /* ← swap this */
--primary-foreground: oklch(0.98 0 0);
--border: oklch(0.22 0 0);
--muted: oklch(0.16 0 0);
--muted-foreground: oklch(0.52 0 0);
--radius: 0.5rem;
}Code
Copy. Paste. Ship.
Every component is a single file. No abstractions, no magic — just clean TypeScript you can read and modify.
"use client"
import { useState } from "react"
import { Eye, EyeOff, ArrowRight, Github } from "@/components/nexui/icons"
export function SignIn() {
const [showPassword, setShowPassword] = useState(false)
const [loading, setLoading] = useState(false)
function handleSubmit(e: React.FormEvent) {
e.preventDefault()
setLoading(true)
setTimeout(() => setLoading(false), 1500)
}
return (
<div className="flex flex-col gap-8 w-full max-w-sm">
<div className="flex flex-col gap-2">
<h1 className="text-2xl font-semibold text-foreground tracking-tight">Welcome back</h1>
<p className="text-sm text-muted-foreground">Sign in to your account to continue.</p>
</div>
<button
type="button"
className="flex items-center justify-center gap-2.5 w-full rounded-xl border border-border bg-secondary hover:bg-secondary/80 text-foreground text-sm font-medium h-11 transition-colors"
>
<Github size={16} aria-hidden="true" />
Continue with GitHub
</button>
<div className="flex items-center gap-3">
<div className="flex-1 h-px bg-border" />
<span className="text-xs text-muted-foreground">or</span>
<div className="flex-1 h-px bg-border" />
</div>
<form onSubmit={handleSubmit} className="flex flex-col gap-4">
<div className="flex flex-col gap-1.5">
<label htmlFor="email" className="text-xs font-medium text-foreground/80 uppercase tracking-wider">
Email
</label>
<input
id="email"
type="email"
autoComplete="email"
placeholder="you@example.com"
required
className="h-11 w-full rounded-xl border border-border bg-secondary px-4 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-all"
/>
</div>
<div className="flex flex-col gap-1.5">
<div className="flex items-center justify-between">
<label htmlFor="password" className="text-xs font-medium text-foreground/80 uppercase tracking-wider">
Password
</label>
<a href="#" className="text-xs text-primary hover:text-primary/80 transition-colors">
Forgot password?
</a>
</div>
<div className="relative">
<input
id="password"
type={showPassword ? "text" : "password"}
autoComplete="current-password"
placeholder="••••••••"
required
className="h-11 w-full rounded-xl border border-border bg-secondary px-4 pr-11 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-all"
/>
<button
type="button"
onClick={() => setShowPassword((v) => !v)}
aria-label={showPassword ? "Hide password" : "Show password"}
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors"
>
{showPassword ? <EyeOff size={16} aria-hidden="true" /> : <Eye size={16} aria-hidden="true" />}
</button>
</div>
</div>
<button
type="submit"
disabled={loading}
className="flex items-center justify-center gap-2 h-11 w-full rounded-xl bg-primary text-primary-foreground text-sm font-semibold hover:bg-primary/90 disabled:opacity-60 transition-all mt-1"
>
{loading ? (
<span className="size-4 rounded-full border-2 border-primary-foreground border-t-transparent animate-spin" />
) : (
<>Sign in <ArrowRight size={15} aria-hidden="true" /></>
)}
</button>
</form>
<p className="text-center text-sm text-muted-foreground">
Don't have an account?{" "}
<a href="/sign-up" className="text-primary font-medium hover:text-primary/80 transition-colors">
Sign up
</a>
</p>
</div>
)
}