Open source
213 components for Phoenix LiveView on Tailwind v4, a test file behind every one, 1.4M downloads. Your agent reads the schema from the MCP server and writes the tag: a handful of tokens, the same on every screen, instead of a block of Tailwind it will never write the same way twice.
Free account, no credit card. Prefer email?
213 components petal_components 4.16 1k stars on GitHub MIT
Writing UI
The invoices table in the dashboard at the top of the page is the first specimen: its file is below, the Amount column left out to fit the panel, and the same call renders live beside it. Every block on this page is real markup from the installed library. Paste one into a template and you get what you see, in both schemes, with focus and keyboard already in it.
<.table rows={@invoices}>
<:col :let={row} label="Invoice">
{row.ref}
</:col>
<:col :let={row} label="Status">
<.badge dot dot_color={row.tone}
color="gray" variant="soft"
label={row.status} />
</:col>
<:col label="">
<.button size="xs" color="gray"
variant="outline"
label="Edit" />
</:col>
</.table>
| Invoice | Status | |
|---|---|---|
| INV-1042 | Paid | |
| INV-1041 | Sent | |
| INV-1040 | Overdue | |
| INV-1039 | Paid |
Rows in, columns as slots. The badge and the row action are two more tags inside it, and there is no class list anywhere in the file.
See the table<.stepper steps={@steps} size="sm"
label_placement="bottom" />
<.badge dot dot_color="success"
color="gray" variant="soft" label="Paid" />
<.badge color="gray" variant="soft" label="Draft" />
Three steps, Draft complete, Sent current and Paid still to come, beside a green Paid badge and a plain Draft one.
A badge and a stepper read the tokens everything else reads, so the colour of "paid" is set once for the whole application.
See the theming contract<.button loading={@saving} label="Saving" />
<.button color="gray" variant="outline" label="Cancel" />
One boolean swaps the label for a spinner and stops the second click. The waiting state is part of the component, not something you wire up around it.
See the buttons<.card>
<.card_content heading="New member">
<.field type="email" name="email"
label="Email" value=""
placeholder="alex@acme.com" />
<.field type="switch"
name="welcome" checked
label="Send a welcome email" />
<.button label="Send invite"
class="w-full" />
</.card_content>
</.card>
Fields carry their own label, error and help text, so a changeset error lands beside the input it belongs to without extra markup.
See the cardInstall
Step one connects your agent to mcp.petal.build, once, on your machine. Step two is a prompt in any Phoenix project: the agent reads the install steps off the server, patches mix.exs, app.css and your web module, and stops. Nothing is copied out of a repository, so an upgrade is a version bump.
claude mcp add petal --transport http https://mcp.petal.build/mcp
// .cursor/mcp.json
{ "mcpServers": { "petal": { "url": "https://mcp.petal.build/mcp" } } }
# ~/.codex/config.toml
[mcp_servers.petal]
url = "https://mcp.petal.build/mcp"
get_install_instructions
the setup steps
list_components
the inventory, one line each
get_component
one component's full schema
install petal_components
Windsurf, Continue and Cline take the same URL in their MCP settings.
Three tools, and the agent picks the one it needs. Drop rules.md into your tool's rules system and it reaches for a component before it reaches for a class list.
Read the rules fileThe answer opens with the component's full name, then lists each attribute with its type, its default and every value it accepts. The button's colour is a closed list of eleven values and its size a closed list of six.
Ask for one component and the answer is its attrs, slots, defaults and allowed values. The agent writes against enums it can see, so a made-up colour never reaches your template.
Read the serverPrefer to do it by hand? The README has the manual steps.
The catalogue
213 components, all reading the same tokens for colour, radius and type. The index is the live list: every component on one page, with its own docs page and full source behind the name.
Enough to build a whole application without leaving the library, and nothing that only makes sense on a marketing site.
Browse the indexSet primary, radius and font on the dials, then copy the CSS out. The same three tokens drive every component in your app, so nothing is restyled one screen at a time.
Open the playgroundThe paid half
Petal Pro is a Phoenix SaaS starting point built on these same components: everything an application needs before the part that is yours, as source you own outright. The best reference there is for composing the library into a working app, because it is one.
Everything above is MIT and needs no sign-in. A free account adds:
Free account, no credit card. Prefer email?
3,383 developers on Petal 1.4M Hex downloads 606 projects registered