Installation
PresetUI has no package. There is nothing to install and nothing to update. Each component is a single JavaScript file that imports nothing but React — you copy it into your project and it becomes your code.
Most components import nothing at all. Only Tabs and Dialog reach for a React
hook, and React is already in your project. Nothing else is ever imported: no
clsx, no tailwind-merge, no headless library. npm run check enforces
that in this repo.
1. Requirements
- React 19 or later — components rely on
refbeing a normal prop, so noforwardRefwrapper is needed. - Tailwind CSS v4 — the theme below uses the
@themedirective.
Plain JavaScript, no TypeScript. Props are documented with JSDoc comments, so editors still autocomplete them.
2. Add the theme
Paste this into your global stylesheet, after @import "tailwindcss";. This is
the only shared code in PresetUI. Every component reads these seven tokens and
nothing else, so changing a value here rebrands the entire kit.
/* PresetUI theme — copy this into your global stylesheet.
Every PresetUI component reads these tokens and nothing else.
To rebrand the kit, change the values here. */
@theme {
/* Core — required. Every component reads these seven. */
--color-surface: #ffffff;
--color-fg: #0a0a0a;
--color-muted: #737373;
--color-border: #e5e5e5;
--color-accent: #0a0a0a;
--color-accent-fg: #ffffff;
--color-danger: #dc2626;
/* Optional — each powers exactly the variants listed beside it. Drop a
line you don't need and only that variant stops working:
--color-success → Alert and Badge, variant="success"
--color-warning → Alert and Badge, variant="warning"
Your own tokens work the same way: define --color-brand here, then use
bg-brand or text-brand inside a component. */
--color-success: #16a34a;
--color-warning: #d97706;
}
.dark {
--color-surface: #0a0a0a;
--color-fg: #fafafa;
--color-muted: #a3a3a3;
--color-border: #262626;
--color-accent: #fafafa;
--color-accent-fg: #0a0a0a;
--color-danger: #ef4444;
--color-success: #22c55e;
--color-warning: #f59e0b;
}Dark mode is a dark class on your <html> element. There is no separate set
of tokens — the same names take different values.
3. Copy a component
Open any component page, switch to the Source tab, and copy the file into
your project. A common home is components/ui/, but nothing depends on the
location.
The Usage tab next to it shows how the component is used once you've copied it — the same code you'd write if it had come from a package.
If you prefer the terminal:
curl -o components/ui/button.js https://presetui.com/r/button.txtFor AI agents
Point your agent at these plain-text endpoints:
/llms.txt— the entire kit, theme and all components, in one document/r/button.txt,/r/input.txt,/r/card.txt,/r/badge.txt— individual sources
A useful instruction: "Read https://presetui.com/llms.txt and write these components into components/ui/ as .js files. Do not install any packages."
One trade-off worth knowing
PresetUI does not use tailwind-merge. Your className is appended after the
component's own classes, so it usually wins — but when two utilities target the
same CSS property, the winner is decided by Tailwind's stylesheet order rather
than by which one you wrote.
In practice this means <Button className="px-8"> works, while overriding
something the component already sets in the same category may need ! :
<Button className="bg-blue-600!">Custom</Button>This is the cost of having no dependencies. If it bothers you, the components
are yours — add tailwind-merge to your copy.