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.
The new part is the MCP server. AI coding assistants (Claude Code, Cursor, Windsurf, Codex) can query the actual component schema before they write any HEEx. No more inventing component APIs from training data. shadcn does not ship one yet. We do.
| shadcn/ui | petal_components | |
|---|---|---|
| Runtime | React | Phoenix LiveView (HEEx) |
| Styling | Tailwind 3 + CSS variables | Tailwind v4 |
| 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 | ~50 | 30+ and growing |
| Underlying primitives | Radix UI for headless behavior | Alpine.js or Phoenix.LiveView.JS |
| AI tool integration | None (training-data guesses) |
Hosted MCP server at
mcp.petal.build
|
| 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.