Skip to content

TanStack Start

Install newt/ui in a TanStack Start app: the root route stylesheet, the alias, and the two commands.

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 create-tsrouter-app@latest
npx create-tsrouter-app@latest
yarn dlx create-tsrouter-app@latest
bunx create-tsrouter-app@latest
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 button
npx newtui@latest add button
yarn dlx newtui@latest add button
bunx newtui@latest add button

TanStack Start 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 create-tsrouter-app@latest
npx create-tsrouter-app@latest
yarn dlx create-tsrouter-app@latest
bunx create-tsrouter-app@latest
pnpm dlx newtui@latest init
npx newtui@latest init
yarn dlx newtui@latest init
bunx newtui@latest init
pnpm dlx newtui@latest add button
npx newtui@latest add button
yarn dlx newtui@latest add button
bunx newtui@latest add button

Create the app

npx create-tsrouter-app@latest my-app --template file-router --tailwind

The template already carries Tailwind v4 through the Vite plugin. An app made without --tailwind needs tailwindcss and @tailwindcss/vite installed and the plugin added to vite.config.ts.

Declare the alias twice

{
  "compilerOptions": {
    "paths": { "@/*": ["./src/*"] }
  }
}
import { fileURLToPath } from "node:url"

import { defineConfig } from "vite"

export default defineConfig({
  resolve: {
    alias: { "@": fileURLToPath(new URL("./src", import.meta.url)) },
  },
})

Run init

pnpm dlx newtui@latest init
npx newtui@latest init
yarn dlx newtui@latest init
bunx newtui@latest init

There is no --template for TanStack Start: the app is created by create-tsrouter-app above, and init reads what it finds — React from the dependencies, the stylesheet from src/styles.css.

Mark the root document

The root route owns the <body>, so .newt-root goes there:

import appCss from "../styles.css?url"

export const Route = createRootRoute({
  head: () => ({ links: [{ rel: "stylesheet", href: appCss }] }),
  component: () => (
    <html lang="en">
      <body className="newt-root">
        <Outlet />
      </body>
    </html>
  ),
})

Add a component

pnpm dlx newtui@latest add button
npx newtui@latest add button
yarn dlx newtui@latest add button
bunx newtui@latest add button
import { Button } from "@/components/ui/button"

export const Route = createFileRoute("/")({
  component: () => <Button variant="primary">Send</Button>,
})

Server rendering

Start renders on the server by default, so the same rule as Next applies: the nine interactive components carry "use client". Answer yes to the React Server Components question at init to keep those directives, no to have add strip them.

What init writes

components.json                 the config, shared with shadcn
src/styles.css                  the --newt-* token block
src/lib/utils.ts                cn()
src/components/ui/button.tsx    add button

See Dark mode for the theme toggle, and RTL if the app has to run right to left.