Proper UI

Installation

This guide walks through installing Proper UI and getting a new or existing project set up quickly.

Frameworks

The CLI detects your project and scaffolds the right files. Pick the framework you're using and run its init command from your project root.

Next.js

npx @properui/cli@latest init --nextjs

Vite

npx @properui/cli@latest init --vite

Bolt, v0, Lovable, Claude

AI builders that can run shell commands can use the same CLI. Run the framework flag that matches the generated project (--nextjs or --vite), or leave it off and let init auto-detect from the project files:

npx @properui/cli@latest init --nextjs

Manual

No CLI, no problem: see Manual installation below for the exact files to create by hand.

Installation via CLI

The CLI creates theme.css, and updates globals.css with the full stylesheet block, not just an @source line: the theme import, plugin registrations, custom variants, and utility layer, inserted right after your existing @import "tailwindcss" line. It adds the cx utility, and, unless you pass --no-providers, copies the registry's ThemeProvider and wires it into your app entry point (plus RouterProvider on a Next.js App Router project). Unless you pass --no-tooling-ignores, it also adds ESLint and Prettier ignore entries for the vendored component directories. For Vite it also wires the @ import alias for you: a paths entry in tsconfig.app.json/tsconfig.json and the matching resolve.alias in vite.config, since Vite needs both to resolve @/... imports and has no built-in tsconfig-paths support. For every other framework it reads your existing tsconfig.json path alias rather than writing one: if none is declared, it warns you and tells you what to add.

init doesn't install any npm packages itself unless you pass --install; either way, it prints the install command last, after every file it wrote, ending with a "Next steps" hint that names real registry entries you can copy and run as-is:

Next steps:
  npx @properui/cli@latest add buttons badges

Once your project is initialized, add components one at a time:

npx @properui/cli@latest add badges

Add as many components as you need; each command copies that component's source (and its dependencies) straight into your project and reports the npm packages the install needs, with per-file attribution, as the last thing it prints:

npx @properui/cli@latest add button-group avatar table

add, remove, and why all read and write an installed manifest kept inside components.json: add records what it wrote, remove <name> deletes an entry's files (warning if something else installed still depends on it), and why <name> prints what pulled an entry in. Run npx @properui/cli@latest check alongside your usual type-check and build to catch raw palette classes or arbitrary values that should have been semantic tokens; see the CLI guide for the full command reference, including icons for installing icon components.

Manual installation

If you'd rather not run the CLI, set the project up by hand.

1. Install the dependencies

npm install react-aria-components tailwind-merge tailwindcss-react-aria-components tailwindcss-animate @tailwindcss/typography

2. Create theme.css

Add a theme.css file with your design tokens inside a Tailwind v4 @theme block: brand palette, semantic colors, typography scale, shadows, and breakpoints. This is the single file to edit when re-branding.

/* theme.css */
@theme {
    --color-brand-50: #f5f8ff;
    --color-brand-500: #2563eb;
    --color-brand-600: #1d4ed8;
    /* ...the rest of the brand scale, plus semantic bg-*/text-*/fg-*/border-* tokens */
}

.dark-mode {
    /* re-map the semantic tokens above for dark mode */
}

3. Update globals.css

Import Tailwind, your theme, and the typography stylesheet, register the plugins, and declare the dark custom variant:

/* globals.css */
@import "tailwindcss";
@import "./theme.css";
@import "./typography.css";

@plugin "@tailwindcss/typography";
@plugin "tailwindcss-react-aria-components";
@plugin "tailwindcss-animate";

@custom-variant dark (&:where(.dark-mode, .dark-mode *));

4. Add the cx utility

Every component merges its style object with cx, a thin wrapper around tailwind-merge that also understands the display-* text sizes:

// utils/cx.ts
import { extendTailwindMerge } from "tailwind-merge";

export const cx = extendTailwindMerge({
    extend: { theme: { text: ["display-xs", "display-sm", "display-md", "display-lg", "display-xl", "display-2xl"] } },
});

5. Copy in a component

With the setup files in place, copy any component's source directly from its page into your project, adjusting import paths to match your aliases.

FAQs