Petal Components is the shadcn-style component system for Phoenix LiveView. Composable HEEx primitives (<.button>, <.modal>, <.table>) plus a hosted MCP server so Claude Code, Cursor, Codex, and Windsurf write idiomatic markup instead of inventing it.
Every component is a plain HEEx tag. Use them in LiveView, dead views, or anywhere Phoenix renders. No JSX, no React, no build step beyond Tailwind.
Override CSS classes with the
pc-*
prefix, swap in your own styles, fork what you don't like. The components are a starting point, not a cage.
The MCP server at
mcp.petal.build
exposes every component's real schema. AI assistants query it before writing HEEx, so they reach for
<.button>
instead of inventing markup.
Step one runs once. Step two works in any Phoenix project, ever.
claude mcp add petal \
--transport http \
https://mcp.petal.build/mcp
Other AI tools: see the per-tool snippets below.
install petal_components
The agent calls get_install_instructions, then patches your mix.exs, app.css, and web module. Works in umbrella apps too.
Prefer to do it by hand? Manual install instructions are on the README.
The MCP runs over HTTP, so any AI tool with MCP support can connect. Use whatever you already have configured. Drop the canonical rules.md into your tool's rules system and the agent reaches for petal_components by default.
claude mcp add petal \
--transport http \
https://mcp.petal.build/mcp
Add to .cursor/mcp.json:
{
"mcpServers": {
"petal": {
"url": "https://mcp.petal.build/mcp"
}
}
}
Add to ~/.codex/config.toml:
[mcp_servers.petal]
url = "https://mcp.petal.build/mcp"
Add to Windsurf settings → MCP servers. Point the URL at
https://mcp.petal.build/mcp
over HTTP.
Add to
~/.continue/config.json
under
mcpServers
with the URL above.
Configure via the Cline MCP settings panel. URL: https://mcp.petal.build/mcp.
Three tools:
get_install_instructions
for the setup steps,
list_components
for the inventory, and
get_component
for one component's full schema. Here is what
get_component
returns for the button:
# PetalComponents.Button.button/1
## Attributes
- `class` (:any) - CSS class
- `color` (:string) - default: `"primary"` - values: `primary`, `secondary`, `info`,
`success`, `warning`, `danger`, `gray`, `pure_white`, `white`, `light`, `dark`
- `disabled` (:boolean) - default: `false`
- `icon` (:any) - name of a Heroicon at the front of the button
- `loading` (:boolean) - default: `false`
- `size` (:string) - default: `"md"` - values: `xs`, `sm`, `md`, `lg`, `xl`
- `variant` (:string) - default: `"solid"` - values: `solid`, `light`, `outline`,
`inverted`, `shadow`, `ghost`
## Slots
- `<:inner_block>`
That schema is introspected straight out of the Hex package, not hand-written, so it is regenerated with every release and cannot drift from the library. The version the server is running is at mcp.petal.build/healthz . The server is MIT licensed: github.com/petalframework/petal-components-mcp .
Three primitives. The rest of the catalogue follows the same shape.
<.card>
<.card_content>
<.form for={@form} phx-submit="save">
<.field field={@form[:name]} label="Name" />
<.field field={@form[:email]} type="email" label="Email" />
<.button type="submit">Save</.button>
</.form>
</.card_content>
</.card>
<.modal title="Edit user" max_width="md">
<.form for={@form} phx-submit="save">
<.field field={@form[:name]} label="Name" />
<.button type="submit">Save</.button>
</.form>
</.modal>
<.table rows={@users}>
<:col :let={user} label="Name">{user.name}</:col>
<:col :let={user} label="Email">{user.email}</:col>
<:col :let={user} label="">
<.button size="xs" variant="outline"
phx-click="edit" phx-value-id={user.id}>
Edit
</.button>
</:col>
</.table>
<.button loading={@saving} phx-click="save">
Save
</.button>
213 components covering the patterns a real Phoenix app needs. The MCP is always the canonical inventory - call
list_components
for the live list, and the
public roadmap
for what is being worked on next.
container, card, accordion, tabs, stepper, skeleton, breadcrumbs
field, text_input, select, checkbox, radio_group, switch, textarea, date_input, file_input
button, button_group, command (⌘K), dropdown, menu, user_dropdown_menu
alert, modal, slide_over, progress, spinner, rating
table, pagination, badge, avatar, marquee, icon, link, typography
navigation_menu (flyout/mega), border_beam, meteors, spotlight_card, number_ticker, confetti, gradient_text, shimmer_text, word_rotate, typing_effect
Same composable-primitives philosophy. Same idea that you own the patterns. Different runtime: HEEx not JSX. Both sit on Tailwind v4, ours on theme tokens rather than CSS variables, and ours is distributed as a Hex package instead of a CLI that copies source into your repo.
Both ship a hosted MCP server. Ours introspects the installed Hex package, so the attrs and slots an agent reads are the ones your app actually compiled against. That is the difference between "AI guesses your component library" and "AI uses your component library correctly."
Petal Pro is the production Phoenix SaaS boilerplate built on these components. Auth (password + OAuth + passwordless + 2FA), multi-tenancy, Stripe billing, background jobs, the full set. Best reference for real-world composition of petal_components in a working SaaS.
One install command for the MCP. One prompt to your AI. The agent handles the rest.
claude mcp add petal --transport http https://mcp.petal.build/mcp
install petal_components