Components
Navigation
PhoenixPaper.AppBar, Drawer, Tabs, Breadcrumbs, and the List family.
App Bar
A horizontal app bar with a leading slot, a title, and trailing actions (renamed from Navbar to match MUI's own naming). This site's own chrome doesn't use one anymore (just a floating theme toggle instead), so here it is on its own.
Colors
Dense variant
With leading/actions (correct contrast)
Pitfall: a Button's text/icon color is always the brand color (text-pp-primary by default) regardless of what it's sitting on: drop one onto a same-colored app bar with no override and it's not just low contrast, it's the exact same color as the background. The demo above overrides with text-pp-on-primary explicitly.
Options
- color
- primary | secondary | tertiary | surface | transparent (default: primary)
- elevation
- resting elevation, 0-24 (default: 4), ignored for color="transparent"
- position
- static | relative | sticky | fixed | absolute (default: static)
- variant
- regular | dense (default: regular), dense shrinks the toolbar row
- paperize
- boolean (default: true)
<.pp_app_bar position="sticky">
<:leading><.pp_drawer_toggle for="app-drawer" /></:leading>
My App
<:actions>
<.pp_button variant="icon"><.pp_icon name="hero-bell" /></.pp_button>
</:actions>
</.pp_app_bar>
<.pp_app_bar :for={color <- ~w(primary secondary tertiary surface transparent)} color={color} class="!static">
{color}
<:actions>
<.pp_button variant="icon"><.pp_icon name="hero-bell" /></.pp_button>
</:actions>
</.pp_app_bar>
<.pp_app_bar variant="dense" class="!static">
Dense variant
</.pp_app_bar>
Drawer
A vertical navigation panel, persistent on large screens and toggled by a mobile drawer below that breakpoint: pure CSS via a hidden checkbox, no JS.
Options
- id
- required: builds the mobile toggle checkbox's id as "#{id}-toggle"
- color
- primary | secondary | tertiary | surface (default: surface), also restyles nested List/ListItem for contrast
- paperize
- boolean (default: true)
- pp_drawer_toggle for=
- a hamburger label pointing at the given drawer's id; works from anywhere on the page
<.pp_app_bar>
<:leading><.pp_drawer_toggle for="app-drawer" /></:leading>
My App
</.pp_app_bar>
<.pp_drawer id="app-drawer" color="primary">
<:header>My App</:header>
<.pp_list>
<.pp_list_item href="/" active={@current_path == "/"}>Home</.pp_list_item>
</.pp_list>
</.pp_drawer>
Tabs
Tabs/Tab/TabPanel switch entirely client-side via Phoenix.LiveView.JS commands fired on click: no server round-trip, no sliding indicator animation (that needs a real layout measurement JS commands can't do).
Basic
Colors
variant="full_width"
Vertical, with icons
Options
- pp_tabs id
- required: shared with every Tab/TabPanel in the group
- pp_tabs orientation
- horizontal | vertical (default: horizontal)
- pp_tabs variant
- standard | scrollable | full_width (default: standard), horizontal only
- pp_tab id / value
- id matches the parent Tabs; value must be unique within the group
- pp_tab default_selected
- boolean, initial selection, uncontrolled (default: false)
- pp_tab color
- primary | secondary | tertiary | error (default: primary), set per Tab, doesn't cascade
- pp_tab :icon
- optional leading icon slot
- pp_tab disabled / ripple / paperize
- same as Button
- pp_tab_panel id / value
- must match the corresponding Tab exactly
<.pp_tabs id="demo-tabs">
<.pp_tab id="demo-tabs" value="one" default_selected>One</.pp_tab>
<.pp_tab id="demo-tabs" value="two">Two</.pp_tab>
<.pp_tab id="demo-tabs" value="three" disabled>Three (disabled)</.pp_tab>
</.pp_tabs>
<.pp_tab_panel id="demo-tabs" value="one" default_selected>Content one.</.pp_tab_panel>
<.pp_tab_panel id="demo-tabs" value="two">Content two.</.pp_tab_panel>
<.pp_tab_panel id="demo-tabs" value="three">Content three.</.pp_tab_panel>
<%!-- with icons, secondary color, vertical orientation --%>
<.pp_tabs id="vertical-tabs" orientation="vertical">
<.pp_tab id="vertical-tabs" value="a" orientation="vertical" color="secondary" default_selected>
<:icon><.pp_icon name="hero-home" /></:icon>
Home
</.pp_tab>
<.pp_tab id="vertical-tabs" value="b" orientation="vertical" color="secondary">
<:icon><.pp_icon name="hero-user" /></:icon>
Profile
</.pp_tab>
</.pp_tabs>
Breadcrumbs
A breadcrumb trail with a separator auto-inserted between :item slots. An item renders as a link when it has href/navigate/patch, or plain current-page text otherwise: whichever item you leave without a link is the current page, same convention as ListItem.
Basic
Custom separator
max_items={3}: click the ellipsis to expand
Options
- pp_breadcrumbs :item href/navigate/patch
- makes that item a link; omit all three for the current page
- pp_breadcrumbs :separator
- a slot, not a string: can hold an icon; defaults to "/"
- max_items
- collapse into an expandable ellipsis beyond this many items (default: 8)
- items_before_collapse / items_after_collapse
- collapsed slice sizes (default: 1 / 1)
- paperize
- boolean (default: true)
<.pp_breadcrumbs>
<:item navigate="/">Home</:item>
<:item navigate="/catalog">Catalog</:item>
<:item>Current product</:item>
</.pp_breadcrumbs>
<%!-- custom separator slot, e.g. an icon --%>
<.pp_breadcrumbs>
<:separator><.pp_icon name="hero-chevron-right" class="size-4" /></:separator>
<:item navigate="/">Home</:item>
<:item navigate="/settings">Settings</:item>
<:item>Profile</:item>
</.pp_breadcrumbs>
<%!-- beyond max_items, collapses with a clickable ellipsis (pure CSS) --%>
<.pp_breadcrumbs max_items={3}>
<:item navigate="/one">One</:item>
<:item navigate="/two">Two</:item>
<:item navigate="/three">Three</:item>
<:item navigate="/four">Four</:item>
<:item>Five</:item>
</.pp_breadcrumbs>
List
A vertical stack of list items, with optional sub-headers to group them. Renders items as links, buttons, or plain rows depending on their own attrs: a linked item ripples on click by default, just like Button. Click Home or Inbox below to see it.
Preview
Options
- pp_list
- the container, role="list"
- pp_list_item href/navigate/patch
- makes it a link; active/disabled/ripple as usual
- pp_list_item :leading / :secondary / :trailing
- optional slots for an icon, a subtitle line, a badge
- pp_list_subheader
- a small uppercase section label
<.pp_list>
<.pp_list_subheader>Main</.pp_list_subheader>
<.pp_list_item navigate={~p"/"}>Home</.pp_list_item>
<.pp_list_item navigate={~p"/inbox"}>Inbox</.pp_list_item>
<.pp_divider />
<.pp_list_subheader>Account</.pp_list_subheader>
<.pp_list_item navigate={~p"/settings"}>Settings</.pp_list_item>
</.pp_list>