Button

Action trigger with multiple variants, sizes, icons, and a loading state.

Basic

.heex
<.button>Save changes</.button>

Variants

.heex
<.button variant="solid">Solid</.button>
<.button variant="surface">Surface</.button>
<.button variant="soft">Soft</.button>
<.button variant="outline">Outline</.button>
<.button variant="dashed">Dashed</.button>
<.button variant="ghost">Ghost</.button>

Colors

.heex
<.button variant="solid" color="primary">Solid</.button>
<.button variant="surface" color="primary">Surface</.button>
<.button variant="soft" color="primary">Soft</.button>
<.button variant="outline" color="primary">Outline</.button>
<.button variant="dashed" color="primary">Dashed</.button>
<.button variant="ghost" color="primary">Ghost</.button>

<.button variant="solid" color="info">Solid</.button>
<.button variant="solid" color="success">Solid</.button>
<.button variant="solid" color="warning">Solid</.button>
<.button variant="solid" color="danger">Solid</.button>

Sizes

.heex
<div class="flex items-center gap-3 flex-wrap">
  <.button size="xs">Extra Small</.button>
  <.button size="sm">Small</.button>
  <.button size="md">Medium</.button>
  <.button size="lg">Large</.button>
  <.button size="xl">Extra Large</.button>
</div>

With icons

.heex
<.button variant="solid" color="primary">
  <.icon name="hero-arrow-down-tray" class="icon" /> Download
</.button>

<.button variant="solid" color="danger">
  <.icon name="hero-trash" class="icon" /> Delete
</.button>

<.button variant="outline">
  Settings <.icon name="hero-cog-6-tooth" class="icon" />
</.button>

<.button variant="dashed">
  <.icon name="hero-funnel" class="icon" /> Filters
</.button>

Icon-only

Pair square sizes with aria-label so screen readers can announce the button. The icon class auto-sizes the glyph.

.heex
<.button size="icon" variant="ghost" aria-label="Search">
  <.icon name="hero-magnifying-glass" class="icon" />
</.button>
<.button size="icon" variant="ghost" aria-label="Filter">
  <.icon name="hero-funnel" class="icon" />
</.button>
<.button size="icon" variant="ghost" aria-label="Settings">
  <.icon name="hero-cog-6-tooth" class="icon" />
</.button>
<.button size="icon" variant="solid" color="primary" aria-label="Download">
  <.icon name="hero-arrow-down-tray" class="icon" />
</.button>

Icon sizes

Square sizes (icon-xs through icon-xl) are tuned for icon-only buttons; nested icons scale automatically.

.heex
<.button size="icon-xs" aria-label="Search">
  <.icon name="hero-magnifying-glass" class="icon" />
</.button>
<.button size="icon-sm" aria-label="Settings">
  <.icon name="hero-cog-6-tooth" class="icon" />
</.button>
<.button size="icon" aria-label="Home">
  <.icon name="hero-home" class="icon" />
</.button>
<.button size="icon-lg" aria-label="Account">
  <.icon name="hero-user" class="icon" />
</.button>
<.button size="icon-xl" aria-label="Notifications">
  <.icon name="hero-bell" class="icon" />
</.button>

Disabled

.heex
<div class="flex items-center gap-3 flex-wrap">
  <.button disabled variant="solid">Solid</.button>
  <.button disabled variant="surface">Surface</.button>
  <.button disabled variant="soft">Soft</.button>
  <.button disabled variant="outline">Outline</.button>
  <.button disabled variant="dashed">Dashed</.button>
  <.button disabled variant="ghost">Ghost</.button>
</div>

Loading

.heex
<div class="flex items-center gap-3">
  <.button variant="solid">
    <.loading class="icon text-white" />
  </.button>

  <.button>
    <.loading class="icon" /> Loading...
  </.button>

  <.button>
    <.loading variant="dots-bounce" class="icon" /> Processing
  </.button>

  <.button
    variant="solid"
    color="info"
    class="overflow-hidden relative"
    phx-click={JS.toggle_attribute({"data-loading", "true"})}
  >
    <span class="w-full block transition-transform duration-300 in-data-loading:translate-y-[calc(100%+1rem)]">
      Click me
    </span>

    <.loading class="text-foreground-info absolute left-1/2 top-1/2 -translate-y-1/2 -translate-x-1/2 opacity-0 transition-opacity duration-300 in-data-loading:opacity-100" />
  </.button>
</div>

Pass href, navigate, or patch and the component renders an anchor element with the same styling.

Destructive with confirmation

Pair data-confirm with destructive actions; the browser confirms before phx-click fires.

.heex
<.button
  variant="solid"
  color="danger"
  phx-click="delete_item"
  phx-value-id="42"
  data-confirm="Delete this item? This cannot be undone."
>
  <.icon name="hero-trash" class="icon" /> Delete item
</.button>

Customization

.heex
<.button class="rounded-full" variant="solid" color="primary">
  Pill Button
</.button>

<.button class="bg-pink-500 hover:bg-pink-600" variant="solid" color="success">
  Custom Color
</.button>

<.button class="w-full" variant="outline">
  Full Width Button
</.button>