shadcn.io is an independent project built on shadcn/ui
A coding agent works the way you do on an unfamiliar codebase: it reads the files, then changes them. How good its UI work is depends on what it can read. With a component package, the important part sits compiled in node_modules and the agent guesses. With shadcn/ui, the component is a file in your project, written in conventions models have met in many codebases. That difference is most of why agents do well with it, and the rest of this page is how to make the most of it with shadcn.io.
The component is a file you own
Install a component and you get its source, not a dependency:
The CLI writes components/ui/button.tsx into your project. When you ask for "a quieter button for the cancel action", the agent opens that file and finds the answer in plain sight:
export const buttonVariants = tv({
// …
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/80",
ghost:
"hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground",
link: "text-primary underline-offset-4 hover:underline",
// destructive, outline, secondary…
},
},
});It uses variant="ghost" because the file says it exists, not because a doc page it half remembers says so. Ask for a new variant and it adds one to the same object, in the same style, and your app has it. There's no theme API to learn and no upstream package to fight: the edit is a diff in your repository, reviewed like any other.
With a packaged library, the agent sees an import and a type definition. The markup, the styles and the states live in compiled code it can't usefully change, so it falls back on what it remembers of that library's API, which is where invented props come from.
The same conventions in every file
Every component is built the same way, so an agent that has read one has read them all:
- Tailwind classes and theme tokens. Colors are
bg-primary,text-muted-foreground,border-input: tokens from your theme, not hex values. Changes stay on-theme and follow dark mode for free. - Parts you compose. A Card is
Card,CardHeader,CardTitle,CardContent, each a thin element withclassName. There's nothing hidden to configure, so "move the action into the header" is an edit to markup the agent can see. data-sloton every part.data-slot="card-title",data-slot="button": stable hooks for styles and tests, the same in each file.cn()for class names. Every component merges yourclassNamethroughcnfromlib/utils.ts, so an override wins without!important.- Variants in one object. Sizes and variants live in one
tv()call at the top of the file.
These are shadcn/ui's conventions, and shadcn/ui is widely used, so they're familiar to models before your project teaches them anything. Our components keep them, on Base UI, Radix UI, React Aria and Ark UI, so what the model knows transfers.
A registry the CLI and your agent can both read
Each component is published as a registry item: JSON with its files, the packages it needs, the other components it uses and any CSS it adds, in shadcn's registry format. One add installs all of it. That's what makes the install step safe to hand to an agent: it runs the same command you would, and the CLI asks before it overwrites a file you've changed.
To keep your token out of commands (and out of an agent's transcript), register our registry by name in components.json and keep the token in .env.local. Your agent then installs @shadcnio/date-picker like any shadcn/ui component. Installation has the setup.
Docs written for models too
Every docs page has a Markdown version at the same URL plus .md, such as /ui/button.md, with the prose, the usage and the API reference, and the site has an index for models at /llms.txt. Signed in, Copy page on any docs page copies the Markdown with every demo's code, ready to paste into a chat. That's the quickest way to give an agent one component's real API when it isn't connected to anything.
The MCP server: the catalog as tools
The shadcn.io MCP server (with Pro) connects your agent to the catalog itself, in any of 38 clients: Claude Code, Cursor, VS Code, Windsurf, Zed and more. Instead of remembering an API, the agent asks for it, for your stack. It reads your package.json for the framework and the primitives, and every answer is for that target.
| Tool | What the agent gets |
|---|---|
search_components | Components by what they do ("date range", "modal"), best first |
get_component | One component in one call: its parts, demos, packages and install command |
get_component_api | The props of one part, with types and defaults, when it isn't sure |
get_demo | A working demo, its imports pointed at your components.json aliases |
get_project_setup | The init for your framework, or the port's setup for Vue, Svelte and Solid |
search_blocks, plan_page | Whole page sections, and a stack of them for a page |
get_design | A brand's DESIGN.md: tokens and rules to style the app with |
A prompt like this is enough:
The agent searches, gets the component for your stack, runs its install command (your editor asks before it does), and adapts the demo to your form. The quickstart connects it in about a minute; all 22 tools have a page each.
Where agents still go wrong
The files and the MCP remove most guessing, not all of it. Common mistakes, and the fix for each:
| Mistake | Fix |
|---|---|
A prop from another library: asChild on a Base UI trigger, render on Radix UI | Point it at the file in components/ui, or let it call get_component_api |
| Importing a component that isn't installed | Add it first, or tell the agent to install what it uses |
| Hex colors and arbitrary values | Ask for theme tokens: "use the theme's colors, no hex" |
Dropping a DialogTitle or a label to tidy the markup | Keep accessible names: a visually hidden title is className="sr-only" |
| Mixing two libraries' files of the same name | Keep one library per app for the shared components |
Two habits help most: install the component before you ask for the feature, and name the file you want changed ("in components/ui/sidebar.tsx…"). The agent then edits what's there instead of recreating it.
FAQ
Why do AI coding tools work better with shadcn/ui than with a component package?
Because the component is source code in your repository. The agent reads the real markup, classes and variants before it changes anything, and its change is an ordinary edit you review. With a package, the implementation is compiled in node_modules, so the agent works from memory of the API and guesses.
Which AI coding tools does this work with?
Any tool that can read and edit files in your project: Claude Code, Cursor, GitHub Copilot, Windsurf, Zed, Codex and the rest. The MCP server is optional on top, and has a setup guide for each of 38 clients.
Do I need the MCP server for an agent to use the components?
No. Once a component is in components/ui, the agent reads it like any file. The MCP adds what isn't in your project yet: finding the right component, its API for your stack, working demos, the install command and the project's setup.
Should I let the agent write components from scratch instead?
For one-off layout, sure. For controls people interact with (menus, dialogs, comboboxes, date pickers), install ours: focus management, keyboard support and screen reader behavior come from Base UI, Radix UI or React Aria, which are hard to get right from scratch and easy to get subtly wrong.
How do I stop an agent from inventing props?
Give it the source of truth: the file in components/ui, the page's Markdown (its URL plus .md), or the MCP's get_component_api. Invented props almost always come from another library's API, like asChild where Base UI uses render.
Does shadcn.io have an llms.txt?
Yes, at /llms.txt: every section of the site as links, each docs page linking its Markdown. Point an agent at it to find a page, then at the page's .md for the details.
If I let the agent change components, how do I get updates later?
Run the component's add again: the CLI shows that your file differs and asks before it overwrites it. Commit first, take the update, and reapply your changes from the diff, or ask the agent to merge them.