Skip to content
TopClass UI

Add with the CLI

Copy a component into your project and own the file.

Initialise once

init detects your framework and package manager, then copies the shared code and edits your CSS.

terminal
$ npx topclassui init

Detected Next.js 16.4.2, App Router, TypeScript 5.9.3, Tailwind 4.3.3
Detected npm (default)
CSS entry  app/globals.css
Folder     topclassui
svg → topclassui/components/svg/ (button imports it)
button → topclassui/components/button/ (toast imports it)
toast → topclassui/components/toast/ (base imports it)
base → topclassui/
Added to app/globals.css:
  @import "../topclassui/tokens.css";
  @import "../topclassui/styles.css";
Wrote 106 files and topclassui.json

It then installs @base-ui/react, class-variance-authority, clsx, tailwind-merge and zod, and prints the provider lines for your layout; it never edits the layout itself. If the layout already mounts the provider from the package, init stops, since the copies read the copied provider; --force goes ahead anyway.

Where, Next.js App Router, Vite
WhereNext.js App RouterVite
Foldertopclassui/, or src/topclassui/ with a src foldersrc/topclassui/
CSS entryapp/globals.csssrc/index.css
Providerapp/layout.tsx, with ThemeScript in the headsrc/main.tsx, around <App />

Add a component

add copies the component and everything it imports. Name one or several, or pass --all.

terminal, version 2
$ npx topclassui add select

select → topclassui/components/select/

# the same command under each package manager
$ pnpm dlx topclassui add select
$ yarn dlx topclassui add select
$ bunx topclassui add select

list prints every component and which ones are in your project; --json prints the same list as JSON.

What lands in your project

One folder for everything we add. Your own code stays untouched.

  • your-app/
  • app/
  • globals.cssinit adds two import lines
  • topclassui/everything of ours, in one folder
  • components/
  • button/init brings it, the toast imports it
  • index.tsxthe component, renders on the server
  • variants.tshow it looks
  • classes.tsits own class constants
  • constants.tsits default values
  • types.tsits props
  • schema.tsprop rules
  • boundaries.tsthe limits it enforces
  • skeleton.tsxloading
  • dummy/working examples, one per file
  • select/npx topclassui add select
  • client.tsxthe interactive part only
  • hook.tsstate, effects, handlers
  • lib.tspure helpers, no React
  • shared/cn, classes, contracts, labels, provider, theme
  • icons/one file for each icon a copy uses
  • tokens.cssevery --tc-* variable
  • styles.cssthe @theme mapping and the variants
  • topclassui.jsonyour settings

Import from the folder, not from the package: import { Button } from '@/topclassui/components/button'. The copies import each other with relative paths.

The config file

Written by init and read by add and diff. lock records each copied file with its version and a hash, so leave it to the CLI.

topclassui.json
{
  "version": 1,
  "framework": "next-app",
  "css": "app/globals.css",
  "dir": "topclassui",
  "imports": "relative",
  "packageManager": "npm",
  "lock": {
    "registry": "0.1.0-beta.3",
    "files": {
      "components/button/index.tsx": { "from": "button", "version": "0.1.0-beta.3", "sha256": "…" }
    }
  }
}

When you have edited a copied file

add never overwrites your edits. diff shows what changed; --overwrite replaces the file and prints the diff first.

terminal, version 3
$ npx topclassui diff select

select: 1 of 20 files differ
  components/select/classes.ts: modified locally

$ npx topclassui add select --overwrite

diff exits with 1 when anything differs. After you update the package, add --update writes the new version of every file you have not touched.

Running without prompts

code
npx topclassui init --yes                # accept every default
npx topclassui add button --yes
npx topclassui add button --dry-run      # print what would be written, write nothing

Every command also takes --cwd <dir> for a project outside the current folder.

Flag, What it does
FlagWhat it does
-y, --yesAccept every default without asking
--dry-runPrint what would be written; write and install nothing
--no-installPrint the install command instead of running it
--css <file>init: the CSS file that imports tailwindcss
--dir <path>init: the folder for the copies
--pm <name>npm, pnpm, yarn or bun
--examples, --no-examplesadd: also add what the examples need, or copy no examples
Exit codes: 0 done, 1 something differs, 2 a mistake in the command, 3 the install failed.

What it never does

No telemetry

It sends nothing. The only download is the install it runs.

Nothing outside its own files

It writes its own folder and topclassui.json, and two lines in your CSS entry.

No silent overwrite

A file you edited is left alone unless you pass --overwrite, and then the diff prints first.