Inspired by shadcn/ui — own every line.

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.

100+Components
0 KBBundle size
100%Yours to edit
MITLicense
terminalwww.nexui.dev
# 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.

Welcome back

Sign in to your account to continue.

or

Don't have an account? Sign up

AuthenticationAuth

Sign-in, sign-up, and multi-step account creation flows with OAuth, password strength validation, and 2FA.

View all components

Explore all components

50+ components across Auth, Chat, Data Views, Charts, Forms, Carousel, and more.

Browse components

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.

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.

$pnpm dlx create-next-app@latest my-app --typescript --tailwind --eslint
Creating a new Next.js app in ./my-app Installing dependencies... Success! Created my-app

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
// 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 NexUIConfig

nexui init

Scaffolds nexui.config.ts, writes the cn utility to lib/utils.ts, and injects CSS variables into globals.css. Run once per project.

$pnpm dlx @jessin/nexui@latest init
Detecting project type... Framework: Next.js (App Router) Writing nexui.config.ts Writing lib/utils.ts Updating app/globals.css NexUI initialized. Run 'nexui add' to add components.

Tip — Run npx @jessin/nexui@latest add with no arguments to open an interactive component picker in your terminal.

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

globals.css
: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;
}
One CSS file controls every component
No theming provider or context required
Works with Tailwind CSS v4 and v3
Dark mode built in by default
Fully typed with TypeScript

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>
  )
}