Skip to content

React Router

Install newt/ui in a React Router framework-mode app: the root layout, 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-react-router@latest
npx create-react-router@latest
yarn dlx create-react-router@latest
bunx create-react-router@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

React Router 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-react-router@latest
npx create-react-router@latest
yarn dlx create-react-router@latest
bunx create-react-router@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-react-router@latest my-app

The default template ships Tailwind v4 and Vite. An app without it needs tailwindcss and @tailwindcss/vite installed and the plugin added to vite.config.ts.

Declare the alias twice

The template already declares ~/*; @/* is the alias init looks for first, and either one works as long as both files agree:

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

import { defineConfig } from "vite"

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

Run init

pnpm dlx newtui@latest init --css app/app.css
npx newtui@latest init --css app/app.css
yarn dlx newtui@latest init --css app/app.css
bunx newtui@latest init --css app/app.css

There is no --template for React Router. --css points init at the stylesheet the root route already links, which is where the tokens belong.

Mark the root layout

export function Layout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <head>
        <Meta />
        <Links />
      </head>
      <body className="newt-root">
        {children}
        <Scripts />
      </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 default function Home() {
  return <Button variant="primary">Send</Button>
}

Server rendering

Framework mode renders on the server, so the nine interactive components keep their "use client" directive. Answering no to the React Server Components question at init has add strip them — which is what an app running in SPA mode wants.

What init writes

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

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