Short version: if you build in React, use shadcn. If you build in Phoenix, use petal_components. Same composable-primitives philosophy. Different runtime. Same idea about AI: ship the schema so coding assistants stop hallucinating.
shadcn won because of three decisions: composable primitives you actually own, no monolithic theme system to fight, and a CLI that drops the source into your repo. The result is a component library that feels like a code generator, not a runtime dependency.
petal_components ports that philosophy to Phoenix LiveView. The primitives are HEEx tags (<.button>, <.modal>, <.table>), built on Tailwind v4, and they work in both LiveView and dead views.
Both libraries now talk to AI coding assistants over MCP. shadcn has an MCP server for browsing and installing registry items. Ours answers a different question. It introspects the petal_components package you have installed and hands back that build's real attrs, slots and enums, so an assistant writes HEEx against your version instead of guessing from training data.
| shadcn/ui | petal_components | |
|---|---|---|
| Runtime | React | Phoenix LiveView (HEEx) |
| Styling | Tailwind v4 + CSS variables | Tailwind v4 + theme tokens |
| Distribution | CLI copies source into your repo |
Hex package,
mix deps.update
|
| You own the code | Yes (copied into your repo) |
Override CSS classes with the
pc-*
prefix
|
| Component count | 64 on their docs index (checked 20 Sep 2026) | 213 HEEx components, read from the installed package |
| Underlying primitives | Radix UI for headless behavior | Alpine.js or Phoenix.LiveView.JS |
| AI tool integration | MCP server over the registry, for browsing and installing items |
Hosted MCP server at
mcp.petal.build
, schema introspected from the installed Hex package
|
| Works in non-JS views | No (React-only) | Yes (live + dead views) |
| License | MIT | MIT |
AI coding assistants are the new package manager. When you ask Claude Code or Cursor to build a settings page, they reach for what they remember from training data. For shadcn that mostly works because the catalogue has been ingested thousands of times. For most component libraries it does not: the agent invents component names, hallucinates attrs, or falls back to raw Tailwind soup.
petal_components ships with a hosted MCP server at mcp.petal.build. AI agents call
list_components
to see the inventory, then
get_component
to fetch the real attr and slot schema for whichever one they are about to use. The schema is generated by introspecting Phoenix.Component.__components__/0, so it cannot drift from the actual library.
One install line:
claude mcp add petal --transport http https://mcp.petal.build/mcp
Then drop the canonical
rules.md
into Cursor, Codex, Continue, or Windsurf and the agent reaches for
<.button>
by default instead of <div class="px-4 py-2 rounded ...">.
A few canonical examples. The mental model is identical. The syntax is what your stack uses.
<Button variant="outline" size="sm">
Save
</Button>
<.button variant="outline" size="sm">
Save
</.button>
<FormField name="email">
<FormLabel>Email</FormLabel>
<FormControl>
<Input type="email" />
</FormControl>
</FormField>
<.field
field={@form[:email]}
type="email"
label="Email"
/>
<Dialog>
<DialogTrigger>Open</DialogTrigger>
<DialogContent>
<DialogTitle>Edit user</DialogTitle>
{/* form */}
</DialogContent>
</Dialog>
<.modal title="Edit user" max_width="md">
<!-- form -->
</.modal>
Catalogue size. shadcn has more components. We are closing the gap on the patterns that actually matter for SaaS apps (the ones AI agents reach for: forms, modals, tables, dropdowns, alerts, navigation), but we are not at parity yet. Roadmap is public.
Behavioral primitives. shadcn is built on Radix, which has been hardened by thousands of teams. Our components use Alpine.js or Phoenix.LiveView.JS, which are simpler but cover a smaller set of edge cases out of the box. For the common patterns this is fine. For unusual accessibility needs in nested keyboard-driven menus, you might do some manual work.
Ecosystem. shadcn has thousands of community recipes, themes, and Figma kits. Our ecosystem is smaller but real: an official Figma kit, VSCode snippets, the MCP, and a production SaaS boilerplate built on top of it.
Step one runs once. Step two runs in any Phoenix project, ever.
claude mcp add petal --transport http https://mcp.petal.build/mcp
install petal_components
The agent calls
get_install_instructions
on the MCP, then patches your mix.exs, app.css, and web module. Works in umbrella apps too. Prefer to install by hand?
Manual instructions
are on the README.