Installation
Three ways in: a preset from the builder, one CLI command, or the wiring for a project you already have.
Choose the brand hue, the radius and the font in newt/create, and it prints a preset code. Pass that code to init and the project comes out already wearing it.
pnpm dlx newtui@latest init --preset <code>npx newtui@latest init --preset <code>yarn dlx newtui@latest init --preset <code>bunx newtui@latest init --preset <code>pnpm dlx newtui@latest add buttonnpx newtui@latest add buttonyarn dlx newtui@latest add buttonbunx newtui@latest add buttonyour framework has no scaffold template, so the project is created by its own tool first and init runs inside the result. It detects the framework, the bundler and the stylesheet on its own.
pnpm dlx newtui@latest initnpx newtui@latest inityarn dlx newtui@latest initbunx newtui@latest initpnpm dlx newtui@latest add buttonnpx newtui@latest add buttonyarn dlx newtui@latest add buttonbunx newtui@latest add buttonPick your framework below. Each guide walks the same four steps: the Tailwind setup, the path aliases, init, and the first component.
Pick your framework
- Next.jsApp Router, server components, app/globals.css.
- Vite (React)React 19, Tailwind through the Vite plugin.
- Vite (Vue)Vue 3.5, Tailwind through the Vite plugin.
- NuxtNuxt 4, with the module that auto-imports the components.
- AstroReact and Vue islands in the same site.
- TanStack StartFull-stack React on TanStack Router.
- React RouterFramework mode, tokens in the root stylesheet.
- LaravelInertia, with the React or the Vue starter kit.
- ManualCopy the source yourself. No CLI, no config file.
- HTML & CSSTwo stylesheets and a class name. No build step.
The first four can be created from nothing: init --template <name> writes the
project and the tokens in one pass. The rest already have a creator of their
own, so their guides start with that command and let init run inside the
result. Manual and HTML & CSS skip the CLI entirely.
What you need first
- Node 18 or newer, which is what both CLIs declare. The Nuxt module asks for Node 20, and this repository itself is built on Node 22.
- React 19 and a Next or Vite project. Vue 3.5 and a Vite or Nuxt project. The components are copied into your source tree, so there is no runtime package to depend on afterwards.
- A Tailwind project. The React registry is developed against Tailwind v3, where
initprints a preset to paste into yourtailwind.config.ts. The Vue registry is developed against Tailwind v4, where the theme is read straight out of the@themeblockinitwrites. It detects the major of whatever project it runs in and writes the other form instead when it has to. - The npm packages
initinstalls for you:class-variance-authority,tailwindcss-animate, and the class merger that matches your Tailwind major —cnon v4,clsxwithtailwind-mergeon v3.
Run init once
pnpm dlx newtui@latest initnpx newtui@latest inityarn dlx newtui@latest initbunx newtui@latest initIt asks a handful of questions and then writes three things. components.json
at the root of your project, which is the same file shadcn reads, so a project
using both CLIs keeps one config and not two. A cn helper at the path your
utils alias names — a re-export of the cn package on Tailwind v4, and clsx
passed through tailwind-merge on v3, whose tables still understand v3 class
names. And the --newt-* token block, appended to the global stylesheet it
found.
The config records your aliases, the stylesheet and the config path it detected,
and two switches: tsx, and rsc for React Server Components. Both change what
add writes later. The default aliases are @/components, @/components/ui,
@/lib, @/lib/utils and @/hooks.
The config records your aliases, the stylesheet and the config path it detected,
whether you are on TypeScript, and whether the project is Nuxt or Vite — it
guesses that from a nuxt.config or a vite.config, and --framework
overrides it. The default aliases are @/components, @/components/ui, @/lib,
@/lib/utils and @/composables.
It does not edit your aliases. It reads them out of tsconfig.json or
jsconfig.json and resolves them to real directories, falling back to src
when that directory exists. A project whose alias is already declared needs
nothing here.
Then add what you need
pnpm dlx newtui@latest add buttonnpx newtui@latest add buttonyarn dlx newtui@latest add buttonbunx newtui@latest add buttonRegistry dependencies are resolved before anything is written, so you name what
you want and get what it is built out of. The modal names the button, which
means add modal on its own writes both. The npm packages the components import
are collected across the whole tree and installed in one pass; pass
--skip-install and the files still land and your package manager is left
alone.
A file already on disk is kept, not replaced: you are asked, and with --yes it
is skipped and reported. --overwrite is how you take the registry version
back. Run add with no names and it lists the registry and lets you pick.
What lands in your project
Every path below the blank line is relative to whatever your aliases resolve to,
so a project with a src directory gets them under src. The two paths above
it are the ones init detected and recorded.
components.json init — the config file
app/globals.css init — the --newt-* token block
lib/utils.ts init — cn(), from the cn package
components/ui/button.tsx add button
components/ui/modal.tsx add modal badge
components/ui/badge.tsxOne file per component, and the imports inside it are rewritten on the way in:
@/registry/bases/newt/ui/button becomes your ui alias, and @/lib/utils becomes
your utils alias. The variants are class-variance-authority, so a component
you want to change is a file you edit.
components.json init — the config file
src/assets/css/tailwind.css init — the --newt-* token block
lib/utils.ts init — cn(), from the cn package
components/ui/button/Button.vue add button
components/ui/button/index.ts
components/ui/modal/Modal.vue add modal badge
components/ui/modal/ModalHeader.vue
components/ui/modal/ModalBody.vue
components/ui/modal/ModalFooter.vue
components/ui/modal/ModalClose.vue
components/ui/modal/index.ts
components/ui/badge/Badge.vue
components/ui/badge/index.tsA folder per component: the single-file components, and an index.ts barrel
that re-exports them along with the class-variance-authority variants. The
imports are rewritten on the way in, so ~~/registry/bases/newt/ui/button
becomes your ui alias and @/lib/utils becomes your utils alias.
The token layer
Every colour, radius, shadow, font and duration in the library is a --newt-*
custom property. The source of truth is one file in the repository,
packages/cli/registry/html/tokens.css, and all three flavours read from it:
the Tailwind theme maps its namespaces onto those variables, and the plain CSS
components use var(--newt-brand) directly.
The same file carries one class, .newt-root, which sets the font family, the
base text colour and font smoothing. Put it on the element that wraps your
application. Then make sure the stylesheet init wrote into is actually loaded:
// the stylesheet init wrote the tokens into
import "./globals.css"export default defineNuxtConfig({
css: ["~/assets/css/tailwind.css"],
})
// on Vite, from your entry instead — src/main.ts
import "./assets/index.css"Per-framework guides
The rest of this page is the flow every project shares. The parts that differ —
the Tailwind setup, the path aliases, where .newt-root goes and which
components need a client boundary — are in the guide for
your framework, and the two flavours that never touch a bundler have guides of their own: Nuxt for the module that auto-imports the components, and HTML & CSS for the copy-paste stylesheets.
Options
-c, --cwd <dir> working directory
-r, --registry <url> registry base url (or NEWT_REGISTRY_URL)
-y, --yes skip confirmation prompts
-d, --defaults use the default configuration (init)
-f, --framework <name> react or vue (init, list)
-b, --bundler <name> the Vue build tool: nuxt or vite (init)
--css <path> path to your global css file (init)
--skip-install skip installing dependencies (init, add)
-o, --overwrite overwrite existing files (add)
-a, --all add every available component (add)
-p, --path <path> the path to add the component to (add)
-t, --type <type> filter by registry item type (list)
--json output as JSON (list)
--legacy use the HTML/CSS CLI (same as newtui-html)
-h, --help display the help
-v, --version display the version number
--registry overrides where items are fetched from, and so does the
NEWT_REGISTRY_URL environment variable. The defaults are
https://newtui.dev/r for React and https://newtui.dev/vue/r for Vue. Beyond
init and add there are two more commands: list, which prints the registry,
and diff, which compares a component you have against the one the registry
currently ships.
The button page is the shortest way to see what one of these files looks like once it is in your project. The registry, both CLIs and the Nuxt module all live in the repository, under Apache-2.0.