Stateless Button component with 6 variants and 7 sizes.
Follows the shadcn/ui Button anatomy adapted for Phoenix LiveView.
Classes are built via PhiaUi.ClassMerger.cn/1 so callers can safely
override individual utilities using the :class attribute.
Variants
| Variant | Use case |
|---|---|
:default | Primary call-to-action |
:destructive | Dangerous or irreversible actions |
:outline | Secondary actions, cancel |
:secondary | Lower-emphasis actions |
:ghost | Minimal emphasis, toolbar actions |
:link | Inline navigation-like actions |
Sizes
| Size | Dimensions |
|---|---|
:default | h-10 px-4 py-2 |
:xs | h-7 px-2 text-xs |
:sm | h-9 px-3 |
:lg | h-11 px-8 |
:icon | h-10 w-10 (square) |
:icon_sm | h-8 w-8 (small square) |
:icon_lg | h-12 w-12 (large square) |
Examples
<.button>Save changes</.button>
<.button variant={:destructive}>Delete account</.button>
<.button variant={:outline}>Cancel</.button>
<.button variant={:secondary}>More options</.button>
<.button variant={:ghost}>Settings</.button>
<.button variant={:link}>View details</.button>
<.button size={:sm}>Compact action</.button>
<.button size={:lg}>Prominent action</.button>
<.button size={:icon} aria-label="Add item">
<.icon name="hero-plus" />
</.button>
<.button phx-click="save" phx-disable-with="Saving…">
Save
</.button>
<.button disabled={true}>Unavailable</.button>
<.button class="w-full">Full width</.button>
<.button size={:xs}>Compact</.button>
<.button size={:icon_sm} aria-label="Remove">✕</.button>
<.button>
<:left_icon><.icon name="hero-arrow-left" /></:left_icon>
Back
</.button>
<.button loading={true}>Saving…</.button>
Summary
Functions
Renders a <button> element with semantic PhiaUI theming.
Functions
Renders a <button> element with semantic PhiaUI theming.
Icon slots and gap: when either left_icon or right_icon is
provided, gap-2 is automatically added to the button's class list so
the icon and label maintain consistent spacing — you do not need to add
margin classes inside the slots.
Loading state: when loading={true}, an animated SVG spinner
(animate-spin h-4 w-4) is prepended to the button content, aria-busy
is set to "true" (announcing the in-progress state to screen readers),
and pointer-events-none opacity-50 is applied to prevent duplicate
submissions while the operation completes.
Disabled + loading: both :disabled and :loading independently
apply pointer-events-none opacity-50. When both are true the button is
non-interactive and visually dimmed — this is intentional and safe.
Examples
<%!-- Primary call-to-action --%>
<.button>Save changes</.button>
<%!-- Destructive action — use a confirmation dialog alongside --%>
<.button variant={:destructive}>Delete account</.button>
<%!-- Icon-only toolbar button with accessible label --%>
<.button size={:icon} aria-label="Open menu">
<.icon name="menu" />
</.button>
<%!-- Left icon adds gap-2 automatically --%>
<.button>
<:left_icon><.icon name="arrow-left" /></:left_icon>
Back
</.button>
<%!-- Right icon with a destructive context --%>
<.button variant={:destructive}>
Delete
<:right_icon><.icon name="trash-2" /></:right_icon>
</.button>
<%!-- Loading state while an async operation is in progress --%>
<.button loading={@saving}>
{if @saving, do: "Saving…", else: "Save"}
</.button>
<%!-- LiveView phx-disable-with alternative (server-driven) --%>
<.button phx-click="save" phx-disable-with="Saving…">
Save
</.button>
<%!-- Full-width block button --%>
<.button class="w-full">Continue</.button>Attributes
variant(:atom) - Visual style variant. Defaults to:default. Must be one of:default,:destructive,:outline,:secondary,:ghost, or:link.size(:atom) - Size variant. Defaults to:default. Must be one of:default,:xs,:sm,:lg,:icon,:icon_sm, or:icon_lg.class(:string) - Additional CSS classes (merged via cn/1, last wins). Defaults tonil.disabled(:boolean) - Disables the button and adds pointer-events-none opacity-50. Defaults tofalse.loading(:boolean) - Shows a spinner and prevents interaction while true. Defaults tofalse.- Global attributes are accepted. HTML attributes forwarded to the <button> element (phx-click, data-, aria-, etc.).
Slots
left_icon- Optional icon rendered to the left of the label.right_icon- Optional icon rendered to the right of the label.inner_block(required) - Button label, text or icon content.