Installation
Set up UI.MD in your project and install your first component.
Setup
Two commands get the full design system into your project.
1. Initialize shadcn
Sets up the shadcn CLI and creates a components.json config in your project root. These components are built on Base UI, the CLI's default style, so no extra flags are needed.
2. Install the whole kit
One command lands the whole core system: every component, the shared utilities, an app/ui-md-tokens.css file holding the full token layer, a docs/ui-md-rules.md file that states the design rules for anyone (or any coding agent) working in the project, a docs/ui-md-changelog.md whose git diff after a pull is your release notes, a style checker at scripts/verify-ui.mjs, and two Claude Code skills. This is the way in: start here so your project is on the system from the first render, not retrofitted onto it later.
Animations work on their own: the kit installs tw-animate-css and wires its @import for the dialogs, dropdowns, popovers, and toasts that need it.
After the install
The command lands the files. These three make them do something, and the first install is the moment they matter most: a project drifts off a design system in its first week, not its tenth.
1. Read the rules, or point your agent at them
docs/ui-md-rules.md is the whole system in one file: the token architecture, the rhythm rungs that own vertical space, the type scale, and the reasoning behind each. It is written to be read by a coding agent as much as a person. Nothing reads it on its own, which is the single most common reason a project ends up with the kit installed and none of its spacing.
2. Wire the checker into your build
{
"scripts": {
"verify:ui": "node scripts/verify-ui.mjs"
}
}Then call it from the build or CI script you already run, so a violation fails the build instead of waiting to be noticed. scripts/verify-ui.mjs ships with the kit and checks your own components, not just your use of ours. Read its warnings as well as its errors: every rhythm rule arrives as a warning first, so a passing run does not yet mean the spacing is on the ladder.
3. Restart your agent session
The kit ships two Claude Code skills: /uimd-pull to update it later, and /uimd-build, which fires when you build a page or change spacing and routes to the rules before the class strings get written. They arrive as files, and a skill added partway through a session is not picked up until the next one starts. Restart before building, or the session that installed the kit is the one session working without it.
Outside Claude Code, that pointer is a managed block in your AGENTS.md, which Codex, Cursor, and anything else that reads one will pick up. An agent running the install writes it for you. It is fenced, so it is safe: the kit only ever touches what sits between its two markers, and a later pull replaces that block to keep it current while leaving everything you wrote above and below it untouched.
<!-- ui-md:begin (managed by the UI.MD kit; edit above or below, never inside) -->
Before writing or changing any UI, read docs/ui-md-rules.md: spacing comes from
the rhythm rungs and type from the scale. Run `npm run verify:ui` before
calling UI work done.
To install or update the UI.MD kit, follow docs/ui-md-upgrade.md exactly.
<!-- ui-md:end -->Own the code, safely
The kit overwrites its own files on every pull, so anything you edit in place is lost. Both ways of making it yours are built to survive that.
-o overwrites, so treat everything under your ui folder as read-only: wrap a component instead of editing it, and your wrapper is never touched. Leave -o off and the CLI asks before replacing each existing file. Re-running the same command is how you update; the next section covers the order that makes an upgrade safe.
Tokens ship as a file rather than as merged CSS variables on purpose. The CLI only ever adds a variable it cannot find, so a project that installed months ago would keep its old palette forever. A file gets overwritten, so a pull is always current. To retune a token, re-declare it in your own global CSS below the import: that file is read after the token file, so your value wins and survives every update.
@import "tailwindcss";
@import "./ui-md-tokens.css";
:root {
--accent: var(--color-accent-600);
}Updating
The install command is also the update command. There is no version number and no migration tool: everything the kit ships is overwritten on every pull, so your own git history is the version record, and a commit before the pull turns the upgrade into a diff you can read.
The order matters, so it reads as one sequence:
git commit -am "before kit pull" # so the diff means something
node scripts/verify-ui.mjs --drift # YOUR edits, before they are reverted
npx shadcn@latest add -o https://ui.mattdowney.com/r/kit.json
git diff docs/ui-md-changelog.md # exactly the entries you had not seen
git diff docs/ui-md-rules.md # exactly the thinking that changed
node scripts/verify-ui.mjs--drift goes before the pull, which is the only time it can help: it lists the installed files you have edited, and the pull is what reverts them.
The changelog diff is the whole cost of the upgrade. Every entry has the same two sections: what moves on screen without you touching your code, and what newly fails the build. A new check arrives as a warning rather than an error, so a pull never breaks your build the day you take it; it is promoted to an error in a later release, and the changelog says when. Everything else is additive.
The kit also installs this sequence as a procedure any coding agent can run: docs/ui-md-upgrade.md, a tool-neutral checklist that commits, checks drift, pulls, reads the changelog, and works the new warnings, asking before it touches anything you customized. Using Codex, Cursor, or anything that reads AGENTS.md? The managed block above points it there, and the install writes it for you. Using Claude Code? It arrives wired as a command: /uimd-pull runs that file. Both update with the kit, like everything else.
Add the extras
The kit runs on four packages: Base UI, Tabler, Motion, and cva. Eight components need a third party package of their own, so they are kept out of it.
Add them with a second command when you want them. Everything updates on every pull, and this command is also its own update command:
| Component | Package it brings |
|---|---|
| Calendar | react-day-picker |
| Carousel | embla-carousel-react |
| Code Block | shiki |
| Command | cmdk |
| Combobox | cmdk (it is built on Command) |
| Rich Text Editor | @tiptap/react and three tiptap extensions |
| Sonner | sonner, next-themes |
| Toast | sonner (it wraps Sonner) |
Both are the same system and the same install command; the split is only about what the convenience bundle drags in. Every one of the eight is still installable on its own by URL, exactly like any other component. A design system you cannot adopt without also installing a rich text editor is asking for more trust than it needs.
Just the tokens?
If you only want the theme and none of the components, install base on its own.
It adds the OKLCH colors, the type scale, and the spacing variables, and nothing else. Most projects should take the kit instead: the tokens without the components leave an agent to hand-roll, which is the most common way a project ends up off the system.
Add a single component
Every component is installable on its own, by URL or by name.
Point the CLI at a component's registry URL:
It downloads the source into your components/ui/ directory and installs the npm dependencies it needs (Base UI primitives, cva, and so on). Swap button for any component name; every component page carries its own copy-paste command.
Or register the namespace once in your components.json, then install by name with no URL:
{
"registries": {
"@uimd": "https://ui.mattdowney.com/r/{name}.json"
}
}What's available
The registry includes components, utilities, and a base theme.
| Item | Description |
|---|---|
| kit.json | The core system in one install, plus the rules, changelog, checker, and upgrade skill |
| kit-extras.json | The eight components that each need a third-party package |
| base.json | OKLCH color tokens, type scale, spacing, shadows, and radii |
| Components | Button, Card, Dialog, Input, Select, Combobox, and more |
| Utilities | cn() class merging, shared layout tokens for cards and modals |
Usage
Import from your local components directory and use like any React component:
import { Button } from "@/components/ui/button"
export function Example() {
return <Button variant="outline">Click me</Button>
}