Components Slide Over

Petal Pro is the full SaaS app this is built for

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

Slide Over

An edge-attached panel (a "sheet") for forms and detail views that don't warrant a full page. Slides from any edge, scrolls its body, pins its footer.
Edit profile sheet

An edge-attached panel for forms that don't warrant a full page. origin slides it from left, right, top or bottom (right here); title and description wire aria-labelledby and aria-describedby; the :footer slot pins the action row below the scrolling body. show_slide_over and hide_slide_over are LiveView.JS commands - no server round-trip to animate.

heex
<.button
color="gray"
variant="outline"
phx-click={show_slide_over("right", "showcase-sheet-profile")}
>
<.icon name="hero-pencil-square" class="w-4 h-4 mr-1" /> Edit profile
</.button>
<.slide_over
id="showcase-sheet-profile"
hide
origin="right"
max_width="md"
title="Edit profile"
description="Make changes to your profile here. Click save when you're done."
>
<div class="flex flex-col gap-4">
<.field type="text" name="profile_name" value="Alex Rivera" label="Name" />
<.field type="text" name="profile_username" value="@alexrivera" label="Username" />
<.field
type="textarea"
name="profile_bio"
value=""
label="Bio"
placeholder="A line about you"
/>
</div>
<:footer>
<.button
color="gray"
variant="outline"
phx-click={hide_slide_over("right", "showcase-sheet-profile")}
>
Cancel
</.button>
<.button phx-click={hide_slide_over("right", "showcase-sheet-profile")}>
Save changes
</.button>
</:footer>
</.slide_over>
A cart - scrolling body, pinned summary

The panel is the floating surface: the body scrolls while the :footer stays put, so totals and the checkout button never leave the screen. Escape and click-away close by default.

heex
<.button
color="gray"
variant="outline"
phx-click={show_slide_over("right", "showcase-sheet-cart")}
>
<.icon name="hero-shopping-bag" class="w-4 h-4 mr-1" /> Open cart
<.badge color="primary" size="sm" label="3" class="ml-2" />
</.button>
<.slide_over
id="showcase-sheet-cart"
hide
origin="right"
max_width="sm"
title="Your cart"
description="3 items"
>
<div class="flex flex-col divide-y divide-gray-100 dark:divide-white/10">
<div
:for={
{name, meta, price} <- [
{"Petal Pro licence", "Single project", "$299"},
{"Petal Pro team", "Unlimited projects", "$599"},
{"Petal stickers", "Pack of 12", "$9"}
]
}
class="flex items-center gap-3 py-4"
>
<div class="flex items-center justify-center flex-none w-12 h-12 rounded-lg bg-gray-100 dark:bg-white/10">
<.icon name="hero-cube" class="w-5 h-5 text-gray-400" />
</div>
<div class="flex-1 min-w-0">
<p class="text-sm font-medium text-gray-900 truncate dark:text-gray-100">{name}</p>
<p class="text-xs text-gray-500 dark:text-gray-400">{meta}</p>
</div>
<p class="text-sm font-medium tabular-nums text-gray-900 dark:text-gray-100">{price}</p>
</div>
</div>
<:footer>
<div class="flex items-center justify-between w-full gap-4">
<div>
<p class="text-xs text-gray-500 dark:text-gray-400">Total</p>
<p class="text-base font-semibold tabular-nums text-gray-900 dark:text-gray-100">
$907
</p>
</div>
<.button phx-click={hide_slide_over("right", "showcase-sheet-cart")}>
Checkout
</.button>
</div>
</:footer>
</.slide_over>
Properties
Attribute Type Default Description
class any nil CSS class
close_on_click_away boolean true whether the slideover should close when a user clicks away
close_on_escape boolean true whether the slideover should close when a user hits escape
close_slide_over_target string nil close_slide_over_target allows you to target a specific live component for the close event to go to. eg: close_slide_over_target={@myself}
description string nil a muted line under the title, for context the panel needs
hide boolean false slideover is hidden
id string "slide-over"
max_width string "md" sets container max-width
one of: "sm", "md", "lg", "xl", "2xl", "full"
on_close {:struct, Phoenix.LiveView.JS} %Phoenix.LiveView.JS{ops: []} additional JS commands to run when the slide over closes
on_open {:struct, Phoenix.LiveView.JS} %Phoenix.LiveView.JS{ops: []} additional JS commands to run when the slide over opens
origin string "right" slideover point of origin
one of: "left", "right", "top", "bottom"
rest global
title string nil slideover title
:footer slot slot a pinned action row at the bottom of the panel (save/cancel buttons)
:inner_block slot slot