Live demo — this example is server-driven; run the showcase locally for the interactive version.

Drawer

A side panel that slides in over (or alongside) the main content. Use for transient details, edit forms, or notification lists. Differs from Sidebar which is always visible.

Examples

Basic

Click "Open drawer" to slide the panel in from the right. Click the X (or anywhere else) to close. Alpine tracks the expanded flag.

Main page content. Click the button to slide the drawer panel in from the right.

Panel title

Drawer panel content — details, edit form, related items.

Panel at end

The default position. On expand, focus moves to the panel header for keyboard and screen-reader users — mirrors PF's onExpand focus management.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut.

Drawer panel header

Panel at start

pf-m-panel-left — the panel slides in from the start (left) edge.

The panel slides in from the start (left) edge — pf-m-panel-left on the drawer root.

Drawer panel header

Panel on bottom

pf-m-panel-bottom — the panel slides up from the bottom. The drawer needs an explicit height.

The panel slides up from the bottom — pf-m-panel-bottom on the drawer root. The drawer needs an explicit height for a bottom panel to be visible.

Drawer panel header

Basic inline

pf-m-inline — the panel takes space from the content instead of overlapping it.

pf-m-inline — the panel shares space with the content instead of overlapping it; no backdrop semantics.

Drawer panel header

Inline panel at end

Inline drawer with the default end position plus focus management on expand.

Inline drawer, panel at the end — pf-m-inline.

Drawer panel header

Inline panel at start

pf-m-inline pf-m-panel-left — inline drawer opening from the start edge.

Inline drawer with the panel at the start (left) — pf-m-inline pf-m-panel-left.

Drawer panel header

Stacked content body elements

Both the content and the panel can stack multiple pf-v6-c-drawer__body elements; padding is opt-in per body (pf-m-padding / pf-m-no-padding).

content-body with padding
content-body

Drawer panel title

Drawer panel body with no padding
Drawer panel body

Modified content padding

Content bodies have no padding by default — pf-m-padding adds it.

Content body with pf-m-padding — drawer content bodies have no padding by default.

Drawer panel header

Modified panel padding

Panel bodies are padded by default — pf-m-no-padding removes it.

The panel body opts out of its default padding with pf-m-no-padding.

Drawer panel header
Drawer panel body with no padding

Additional section above drawer content

A pf-v6-c-drawer__section outside __main stays full-width — the panel never overlaps it.

drawer-section above the drawer content

A pf-v6-c-drawer__section sits outside __main — above the content and panel.

Drawer panel header

Static

static=truepf-m-static — panel is permanently visible, no toggle.

pf-m-static — the panel is always shown, no toggle. Useful for split-pane layouts.

Static panel — always visible.

Breakpoint

Panel width via pf-m-width-33; all width modifiers accept -on-lg-style breakpoint suffixes.

The panel width is set with pf-m-width-33 — width modifiers (25/33/50/66/75/100) also come in -on-lg / -on-xl forms.

Drawer panel header

Resizable at end

pf-m-resizable + a splitter. Drag (or focus the splitter and press the arrow keys) to resize; the phaDrawerResizable Alpine factory updates the panel's flex-basis custom property.

Drag the splitter (or focus it and use the arrow keys) to resize the panel. Minimum size 150px, default 500px.

Drawer panel header

Resizable at start

Resizable panel on the start (left) edge.

Resizable panel on the start side — the splitter sits on the panel's trailing edge.

Drawer panel header

Resizable on bottom

Bottom panel with a horizontal splitter — resize with drag or the up/down arrow keys.

Resizable bottom panel — the splitter is horizontal and arrow keys resize vertically.

Drawer panel header

Resizable on inline

Inline + resizable — content reflows while dragging.

Resizable panel in an inline drawer.

Drawer panel header

Panel with secondary background

pf-m-secondary on the panel, content, or section switches that region to the secondary background color variant.

drawer-section

Toggle the checkboxes to flip each region between default and secondary background.

Drawer panel header
Drawer panel body

With focus trap

While open, Tab cycles inside the panel only (PHA.trapFocus); Escape closes it. The panel gets role="dialog".

While the panel is open, Tab cycles only through the panel's focusable elements; Escape closes it.

Pill

pf-m-pill — the panel floats over the content as a detached, rounded pill.

pf-m-pill — the panel renders as a detached, rounded "pill" floating over the content.

Drawer panel header
Drawer panel body

Pill inline

Pill styling combined with pf-m-inline — the rounded panel shares space with the content.

Pill panel in an inline drawer — pf-m-pill pf-m-inline.

Drawer panel header
Drawer panel body

Documentation

Drawer props

The drawer is a template family: drawer is the root (it owns the expanded Alpine state and the bound pf-m-expanded class) and the structure comes from drawer-section / drawer-main / drawer-content / drawer-body / drawer-panel / drawer-panel-main / drawer-head includes composed in main blocks — no generic slot names to collide with outer templates.

* required
Name Type Description
id String DOM id on the drawer root.
inline / static / pill / panelLeft / panelBottom Boolean The matching pf-m-* modifier; static also starts expanded.
startExpanded Boolean Start with the panel open without pf-m-static.
resizable + defaultSize / minSize Boolean + px Uses the phaDrawerResizable Alpine factory; pair with drawer-panel resizable=true for the splitter.
attrs String (raw) Raw attribute passthrough on the root (styles, Alpine directives). Shadowed inside the family's inserts.
drawer-section / drawer-main / drawer-content / drawer-panel-main Include Structural wrappers — main-block content.
drawer-body Include Repeatable body section; padding / noPadding modifiers.
drawer-panel Include resizable (splitter wired to the factory, orientation follows panelBottom), secondary, panelWidth (e.g. "pf-m-width-33"), attrs.
drawer-head Include Title row; main block is the title content. Renders the close button (wired to expanded) unless noClose.

Usage

Pair with a trigger. The runtime template manages the expanded state via Alpine. Dispatch from an outside trigger by setting expanded = true through a shared Alpine store or by re-rendering the drawer with HTMX.

Resizable panels. Load /web/js/alpine/components/drawer-resizable.js and use x-data="phaDrawerResizable" with data-position, data-default-size and data-min-size on the drawer root. The splitter needs role="separator" and wires @pointerdown="startResize" / @keydown="keyResize".