The Proper UI CLI copies component source into your project and configures Tailwind, straight from the terminal — no copy-pasting required.
The properui CLI copies component source into an existing project, shadcn-style — you get the .tsx files, not a runtime dependency. It detects your framework, TypeScript setup, and Tailwind version automatically, then writes files and installs dependencies for you. This guide covers every command: init, add, list, search, diff, and login.
Installation
There's nothing to install ahead of time — every command runs through npx (or your package manager's equivalent), which always fetches the latest version:
npx @properui/cli@latest init
Or with your preferred package manager: pnpm dlx properui@latest init, yarn dlx properui@latest init, bunx properui@latest init.
Requires Node 20+.
Init command
init configures an existing project — it does not scaffold a new one, so run it from the directory that already holds your package.json. It reads your tsconfig.json for an existing path alias, detects Next.js App Router vs Pages Router vs Vite vs Remix vs plain React, checks your Tailwind version (v3 projects are stopped with upgrade instructions — Proper UI requires Tailwind v4), and confirms your package manager from the lockfile. It then writes components.json, copies the theme token file (from the registry when reachable, a placeholder otherwise), creates utils/cx.ts, adds the Tailwind @source scan line and theme import to your global stylesheet, and wraps your app entry point (app/layout.tsx, pages/_app.tsx, or main.tsx) in ThemeProvider. For Vite specifically, it also writes the @ alias into both halves Vite needs — a paths entry in tsconfig.app.json/tsconfig.json and a matching resolve.alias in vite.config — since Vite has no built-in tsconfig-paths support and vite build/tsc -b fail on @/... imports without both. It does not install any npm packages itself — add is what installs a component's dependencies.
npx @properui/cli@latest init
Command options
| Option | Description |
|---|---|
--nextjs | Treat the project as Next.js instead of auto-detecting. |
--vite | Treat the project as Vite instead of auto-detecting. |
--manual | Write the files but leave the app entry point (and, for Vite, the @ alias) alone — print the snippet instead. |
--overwrite | Replace components.json and any files that already exist. |
--registry <source> | Registry directory or base URL for this run (see below). |
-y, --yes | Accept every default; never prompt. |
--cwd <path> | Run against a directory other than the current one. |
Add command
add resolves a component and its registryDependencies recursively, copies the source files into your project, rewrites @/ imports to your configured alias, and installs any missing npm packages.
npx @properui/cli@latest add button
Add multiple components in one call:
npx @properui/cli@latest add button input select
If a component depends on another component internally — badge-groups depends on badges, for example — the CLI pulls in the whole dependency chain, so you never end up with a broken import.
npx @properui/cli@latest add badge-groups
The dependency tree above installs badges and dot-icon alongside badge-groups because those are its registryDependencies.
Install every component at once:
npx @properui/cli@latest add --all
Customize the installation directory:
npx @properui/cli@latest add button --path src/components/ui
Typing a name that doesn't exist gets a suggestion rather than a bare failure — the CLI runs a fuzzy match against the registry index and prints the closest names.
Command options
| Option | Description |
|---|---|
--all | Add every component in the registry. |
--overwrite | Replace files that already exist instead of skipping them — how you pull upstream fixes. |
--path <dir> | Put component files in this directory instead of the configured alias. |
--dry-run | Print what would change without writing anything. |
--registry <source> | Registry directory or base URL for this run (see below). |
-y, --yes | Skip the "install these dependencies?" confirmation. |
--dry-run before --all is a good habit:
npx @properui/cli@latest add --all --dry-run
List command
list prints the registry’s index — every component and example with its layer and description:
npx @properui/cli@latest list
npx @properui/cli@latest list --layer base
npx @properui/cli@latest list --type component
npx @properui/cli@latest list --json
Command options
| Option | Description |
|---|---|
--layer <l> | Filter by layer, e.g. base, application, marketing, app-examples, marketing-examples, foundations, shared-assets, hooks, utils, styles. |
--type <t> | Filter by type: component, example, util, hook, style. |
--json | Print the raw index rows, for scripting. |
Search command
search runs a local fuzzy match over component names, descriptions, and example names — a scored subsequence match, not a network call or an AI model. It rewards contiguous, early, and whole-word matches, so "date picker" still finds date-picker, but it only ranks results that are actually a subsequence of the query; it can't reason about what a component looks like or means.
npx @properui/cli@latest search "pricing"
npx @properui/cli@latest search "empty state" --limit 5
Each line of output shows the matched name, its layer, its title, and how many examples reference it, sorted by score.
Command options
| Option | Description |
|---|---|
--limit <n> | Maximum results (default 20). |
--registry <source> | Registry directory or base URL for this run (see below). |
Diff command
diff compares the files already in your project against the current registry version, so you can see what you've changed (or what's out of date) before pulling an update:
npx @properui/cli@latest diff # every installed component
npx @properui/cli@latest diff button # just one
Requires components.json, so run init first.
Adding example pages
add example installs a complete, functional page — a dashboard, a settings screen, a marketing landing page — along with every component and dependency it uses.
npx @properui/cli@latest add example settings-01
npx @properui/cli@latest add example hero-split-image-01
Once an example is installed, it's your code: modify, delete, or extend it however your project needs. The CLI never re-writes an example file after it's on disk unless you pass --overwrite.
Not sure of the exact name? List them first:
npx @properui/cli@latest list --type example
add example accepts the same options as add (--overwrite, --path, --dry-run, --registry, -y/--yes); there's no separate flag to skip an example's dependencies.
Login command
login stores a registry token at ~/.properui/auth.json. It's only needed for a private registry — the public one is anonymous, and add works without ever logging in.
npx @properui/cli@latest login
npx @properui/cli@latest login --token <token>
Run with no --token in an interactive terminal and it prompts you to paste one (after pointing you at <registry>/account/tokens to create it). The token is reused by every later command on the same machine — you only need to do this once.
Command options
| Option | Description |
|---|---|
--token <t> | Use this token instead of prompting for one. |
--registry <source> | Registry directory or base URL to store the token against. |
-y, --yes | Never prompt — fails with an error if no token is given. |
Pointing at another registry
A registry source is either an HTTP(S) base URL or a directory on disk. Both expose the same shape: index.json plus one <name>.json per entry. Every command accepts --registry <source>, and the source is resolved in this order:
--registry <source>on the command line- the
REGISTRY_URLenvironment variable - the
registryfield incomponents.json - the built-in default,
https://properui.dev/r
The hosted registry at https://properui.dev/r goes live when the docs site deploys. Until then, working from a clone of this repo, build the registry locally and point the CLI at the output directory:
pnpm registry:build
npx @properui/cli@latest add button --registry ./packages/registry/dist
# or: REGISTRY_URL=./packages/registry/dist npx @properui/cli@latest add button
Usage examples
Configure an existing Next.js project and add a handful of base components:
npx @properui/cli@latest init --nextjs
npx @properui/cli@latest add button input select badges avatar
Configure an existing Vite app, then preview what an add --all would do before committing to it:
npx @properui/cli@latest init --vite
npx @properui/cli@latest add --all --dry-run
Search for a layout, install it, and overwrite it later once you've pulled in an update:
npx @properui/cli@latest search "hero split image"
npx @properui/cli@latest add example hero-split-image-01
npx @properui/cli@latest add example hero-split-image-01 --overwrite
Troubleshooting
"No components.json found." Run init first, from the directory that holds your package.json.
Imports point at the wrong place. The alias in components.json no longer matches tsconfig.json. Fix the tsconfig path and re-run init --overwrite.
A component installed but renders unstyled. Your stylesheet is missing the @source line for the directory the components landed in. See Installation.
Debugging. Set PROPERUI_DEBUG=1 to get a full stack trace instead of a single error line.