Components Dropdowns

Petal Pro is the full SaaS app this is built for

Auth, billing, admin, and Claude Code integration included. One purchase, unlimited projects.

Menus on the floating-panel surface: group labels, separators, icons, keyboard hints and destructive items.
Account menu

Menus on the floating-panel surface. label renders the built-in trigger - deliberately neutral gray whatever your palette, only its focus ring rides primary. dropdown_menu_label and dropdown_menu_separator organise groups; items take arbitrary content - icons, .pc-kbd hints, a custom class for the destructive one - and render as a, live_patch, live_redirect or button via link_type.

heex
<.dropdown label="you@example.com">
<.dropdown_menu_label>My account</.dropdown_menu_label>
<.dropdown_menu_item link_type="button">
<.icon name="hero-user" class="w-4 h-4" /> Profile
<kbd class="pc-kbd ml-auto"><span></span><span></span>P</kbd>
</.dropdown_menu_item>
<.dropdown_menu_item link_type="button">
<.icon name="hero-credit-card" class="w-4 h-4" /> Billing
</.dropdown_menu_item>
<.dropdown_menu_item link_type="button">
<.icon name="hero-cog-6-tooth" class="w-4 h-4" /> Settings
<kbd class="pc-kbd ml-auto"><span></span>,</kbd>
</.dropdown_menu_item>
<.dropdown_menu_separator />
<.dropdown_menu_label>Team</.dropdown_menu_label>
<.dropdown_menu_item link_type="button">
<.icon name="hero-user-plus" class="w-4 h-4" /> Invite members
</.dropdown_menu_item>
<.dropdown_menu_item link_type="button" disabled>
<.icon name="hero-plus" class="w-4 h-4" /> New team (Pro)
</.dropdown_menu_item>
<.dropdown_menu_separator />
<.dropdown_menu_item link_type="button" class="text-danger-600 dark:text-danger-400">
<.icon name="hero-arrow-right-start-on-rectangle" class="w-4 h-4" /> Sign out
<kbd class="pc-kbd ml-auto"><span></span><span></span>Q</kbd>
</.dropdown_menu_item>
</.dropdown>
Row actions and a custom trigger

No label renders the ghost ellipsis - the table-row actions trigger. For a branded trigger, :trigger_element is your own button (style it with trigger_class); this one goes solid and follows your colour dials. placement drops the panel left or right of the trigger.

heex
<div class="flex items-start justify-center gap-16">
<.dropdown>
<.dropdown_menu_item link_type="button">
<.icon name="hero-pencil-square" class="w-4 h-4" /> Edit
<kbd class="pc-kbd ml-auto"><span></span>E</kbd>
</.dropdown_menu_item>
<.dropdown_menu_item link_type="button">
<.icon name="hero-document-duplicate" class="w-4 h-4" /> Duplicate
<kbd class="pc-kbd ml-auto"><span></span>D</kbd>
</.dropdown_menu_item>
<.dropdown_menu_item link_type="button">
<.icon name="hero-archive-box" class="w-4 h-4" /> Archive
</.dropdown_menu_item>
<.dropdown_menu_separator />
<.dropdown_menu_item link_type="button" class="text-danger-600 dark:text-danger-400">
<.icon name="hero-trash" class="w-4 h-4" /> Delete
<kbd class="pc-kbd ml-auto"><span></span></kbd>
</.dropdown_menu_item>
</.dropdown>
<.dropdown placement="right" trigger_class="pc-button pc-button--primary pc-button--md">
<:trigger_element>
Move to project <.icon name="hero-chevron-down" class="w-4 h-4 ml-1" />
</:trigger_element>
<.dropdown_menu_label>Recent</.dropdown_menu_label>
<.dropdown_menu_item link_type="button">petal_components</.dropdown_menu_item>
<.dropdown_menu_item link_type="button">petal_pro</.dropdown_menu_item>
<.dropdown_menu_item link_type="button">marketing site</.dropdown_menu_item>
</.dropdown>
</div>
Properties
<.dropdown>
Attribute Type Default Description
class any nil any extra CSS class for the parent container
label string nil labels your dropdown option
menu_items_wrapper_class any nil any extra CSS class for menu item wrapper container
on_close {:struct, Phoenix.LiveView.JS} %Phoenix.LiveView.JS{ops: []} additional JS commands to run when the dropdown closes (LiveView.JS only)
options_container_id string
placement string "left"
one of: "left", "right"
rest global
trigger_class string nil additional classes for the trigger button
:inner_block slot slot
:trigger_element slot slot custom trigger content. Rendered INSIDE the dropdown's own <button>, so never nest interactive elements (<.button>, links) here - browsers split nested buttons and the toggle binding breaks. Style the built-in trigger via trigger_class instead, e.g. trigger_class="pc-button pc-button--primary pc-button--md"
<.dropdown_menu_item>
Attribute Type Default Description
class any nil any additional CSS classes
disabled boolean false
label string link label
link_type string "button"
one of: "a", "live_patch", "live_redirect", "button"
rest global
to string nil link path
:inner_block slot slot
<.dropdown_menu_label>
Attribute Type Default Description
class any nil any additional CSS classes
rest global
:inner_block slot slot
<.dropdown_menu_separator>
Attribute Type Default Description
class any nil any additional CSS classes
rest global