Installation
One command configures components.json, installs the Uqudo theme and registers the @uqudo namespace.
You only do this once per project. Afterwards every item is available as
@uqudo/<name>.
Prerequisites
A Next.js project with Tailwind CSS v4 and a globals.css that starts with
@import "tailwindcss";. Nothing else — the preset below writes
components.json for you.
Set up
The init-uqudo-ui preset does three things in one go:
it writes our components.json settings (Radix radix-rhea style, Lucide icons,
RTL on), installs the theme as app/uqudo-theme.css and
registers the @uqudo namespace.
Apply the preset
Pick the command that matches your project.
npx shadcn@latest init --preset "https://ui-components.dev.uqudo.io/r/init-uqudo-ui.json?base=radix" --yesKeep ?base=radix and the quotes. Without the parameter the CLI assumes Base
UI and the components will not match the ones documented here.
After it runs you have:
Clean up globals.css
The CLI added @import "./uqudo-theme.css"; to the top of globals.css, but it
cannot delete what was already there. Remove the :root and .dark blocks —
they sit after the import, so they would override the Uqudo tokens.
@import "tailwindcss";
@import "tw-animate-css";
@import "shadcn/tailwind.css";
@import "./uqudo-theme.css";
@custom-variant dark (&:is(.dark *));
@theme inline {
/* keep — maps tokens to Tailwind utilities */
}
:root {
--background: oklch(1 0 0);
/* ... */
}
.dark {
--background: oklch(0.145 0 0);
/* ... */
}
@layer base {
/* keep */
}Keep @custom-variant dark, @theme inline and @layer base. If those
blocks held project-specific variables, move them into a new :root after
the import — anything declared there overrides the theme on purpose.
Load Inter
The theme's --font-sans reads a --font-inter variable. Provide it with
next/font on the root element:
import { Inter } from "next/font/google"
const inter = Inter({ subsets: ["latin"], variable: "--font-inter" })
export default function RootLayout({ children }) {
return (
<html lang="en" className={inter.variable}>
<body>{children}</body>
</html>
)
}Ignore installed files
Each item writes .registry/<name>.json with the paths it owns. Hook ESLint
and Prettier once so those files are skipped. After that, a new add is
enough — do not edit ignore lists per item.
import { getRegistryIgnores } from "./.registry/ignore.mjs"
export default [
{ ignores: getRegistryIgnores() },
// ...your existing config
]{
"scripts": {
"format:check": "node .registry/ignore.mjs prettier --check .",
"format:fix": "node .registry/ignore.mjs prettier --write ."
}
}The helper never rewrites eslint.config.mjs or .prettierignore.
Install an item
npx shadcn@latest add @uqudo/buttonDependencies resolve on their own — sidebar pulls in button, sheet,
tooltip, the use-mobile hook and the
registry ignore helper, and installs the cn and
radix-ui npm packages it needs.
Where files land
UI primitives are written to components/uqudo/ui/ rather than components/ui/,
so they sit alongside your own components without overwriting them. Blocks land
one level up in components/uqudo/, hooks in hooks/.
Swapping a project from its own shadcn copy to the registry is therefore a one-line change per import:
- import { Button } from "@/components/ui/button"
+ import { Button } from "@/components/uqudo/ui/button"Without the preset
If you would rather not touch components.json settings, register the namespace
and pull the theme in on its own. Set "style": "radix-rhea" and
"iconLibrary": "lucide" by hand so installed components match.
npx shadcn@latest registry add "@uqudo=https://ui-components.dev.uqudo.io/r/{name}.json"
npx shadcn@latest add @uqudo/themeKeep the quotes. Without them your shell will try to expand {name} and the
registry URL ends up wrong.
A single item can be installed straight from its URL only if it has no
registryDependencies. Every Uqudo item depends on @uqudo/registry-ignore,
so register the namespace and install by name.
Updating an item
Re-run add. The CLI overwrites the files, so review the diff before committing
— any local edits to those files are lost. Files that already exist, such as
uqudo-theme.css, are only replaced with --overwrite.
npx shadcn@latest add @uqudo/button
npx shadcn@latest add @uqudo/theme --overwriteBrowsing the registry
The catalog is a plain JSON document you can open, script against, or point an MCP-enabled assistant at:
https://ui-components.dev.uqudo.io/r/registry.json