33 navigation components — sidebar, topbar, breadcrumbs, tabs, pagination, command palette, table of contents, and mobile navigation patterns.
Module: PhiaUi.Components.Navigation
import PhiaUi.Components.NavigationTable of Contents
App Shell
Primary Navigation
Tabs
Breadcrumbs & Steps
Pagination
Contextual Navigation (v0.1.10)
- command_palette
- toc — Table of Contents
- back_to_top
- page_progress
- link_group
- context_nav
- nav_rail
Mobile & Overlay Nav
sidebar
Fixed sidebar navigation panel. Collapsible. Use inside shell/1.
<.shell>
<:sidebar>
<.sidebar>
<:brand>
<div class="flex items-center gap-2 px-4 py-3">
<img src="/logo.svg" class="h-6 w-6" alt="Logo" />
<span class="font-semibold">MyApp</span>
</div>
</:brand>
<:nav_items>
<.sidebar_item icon="home" href="/" active={@active == :home}>Dashboard</.sidebar_item>
<.sidebar_item icon="users" href="/users" active={@active == :users}>Users</.sidebar_item>
<.sidebar_item icon="bar-chart-2" href="/analytics" active={@active == :analytics}>Analytics</.sidebar_item>
<.sidebar_item icon="settings" href="/settings" active={@active == :settings}>Settings</.sidebar_item>
</:nav_items>
<:footer_items>
<.sidebar_item icon="help-circle" href="/help">Help</.sidebar_item>
<.sidebar_item icon="log-out" phx-click="logout">Sign out</.sidebar_item>
</:footer_items>
</.sidebar>
</:sidebar>
<:main>
<%= @inner_content %>
</:main>
</.shell>topbar
Sticky top bar with logo, search, actions, and user menu slots.
<.topbar>
<:left>
<.mobile_sidebar_toggle target="main-sidebar" />
<.inline_search phx-change="search" />
</:left>
<:right>
<.dark_mode_toggle />
<.badge_button count={@notifications} phx-click="open_notifications">
<.icon name="bell" />
</.badge_button>
<.avatar size="sm">
<.avatar_image src={@user.avatar_url} />
<.avatar_fallback name={@user.name} />
</.avatar>
</:right>
</.topbar>tabs
Content tabs with URL or state-driven active panel.
Variants: :underline · :solid · :pill · :scrollable
<.tabs active={@tab} on_change="set_tab">
<:tab value="overview">Overview</:tab>
<:tab value="activity">Activity</:tab>
<:tab value="settings">Settings</:tab>
<:panel value="overview">
<.overview_panel />
</:panel>
<:panel value="activity">
<.activity_list />
</:panel>
<:panel value="settings">
<.settings_form />
</:panel>
</.tabs><%!-- Pill variant --%>
<.tabs active={@tab} on_change="set_tab" variant={:pill}>
<:tab value="all">All</:tab>
<:tab value="active">Active</:tab>
<:tab value="archived">Archived</:tab>
</.tabs>tabs_nav
Standalone tab navigation bar — use when the tab panels are managed separately.
<.tabs_nav active={@tab} on_change="set_tab" variant={:underline}>
<:tab value="profile">Profile</:tab>
<:tab value="security">Security</:tab>
<:tab value="billing">Billing</:tab>
</.tabs_nav>
<div class="mt-4">
<%= if @tab == "profile", do: live_render(@socket, ProfileLive) %>
</div>breadcrumb
Accessible breadcrumb trail with separator.
<.breadcrumb>
<:item href="/">Home</:item>
<:item href="/products">Products</:item>
<:item href="/products/electronics">Electronics</:item>
<:item>MacBook Pro</:item>
</.breadcrumb>stepper_nav
Multi-step wizard progress indicator.
<.stepper_nav current={@step} total={4}>
<:step label="Account" />
<:step label="Profile" />
<:step label="Plan" />
<:step label="Confirm" />
</.stepper_nav>Attrs: current (1-based integer), total (integer), on_step (event name for clicking completed steps)
pagination
Offset-based pagination with page numbers.
<.pagination
page={@page}
total_pages={@total_pages}
on_page="goto_page"
/>Attrs: page, total_pages, on_page (event name), show_edges (boolean, show first/last buttons)
cursor_pagination
Previous / Next cursor-based pagination for infinite data.
<.cursor_pagination
previous_cursor={@prev_cursor}
next_cursor={@next_cursor}
on_prev="paginate_prev"
on_next="paginate_next"
/>def handle_event("paginate_next", _params, socket) do
{:noreply, assign(socket, data: fetch_page(socket.assigns.next_cursor))}
endload_more
"Load more" button for append-style pagination.
<.load_more
loading={@loading_more}
has_more={@has_more}
on_load="load_more"
label="Load more posts"
/>command_palette
⌘K command palette with groups, items, empty state, and keyboard navigation. Hook: PhiaCommand.
<.command_palette id="cmd" open={@cmd_open} on_close="close_cmd">
<.command_palette_group label="Navigation">
<.command_palette_item icon="home" href="/" shortcut="G H">Dashboard</.command_palette_item>
<.command_palette_item icon="users" href="/users" shortcut="G U">Users</.command_palette_item>
</.command_palette_group>
<.command_palette_group label="Actions">
<.command_palette_item icon="plus" phx-click="new_project">New Project</.command_palette_item>
<.command_palette_item icon="upload" phx-click="import">Import data</.command_palette_item>
</.command_palette_group>
<.command_palette_empty>No results found.</.command_palette_empty>
</.command_palette><%!-- Trigger --%>
<.button variant="outline" phx-click="open_cmd" class="gap-2">
<.icon name="search" size="sm" />
Search…
<.kbd>⌘</.kbd><.kbd>K</.kbd>
</.button>toc
Auto-generated table of contents with active section highlighting. Hook: PhiaToc.
<aside class="sticky top-20">
<.toc id="article-toc" label="On this page">
<.toc_item href="#introduction" depth={1}>Introduction</.toc_item>
<.toc_item href="#installation" depth={1}>Installation</.toc_item>
<.toc_item href="#configuration" depth={2}>Configuration</.toc_item>
<.toc_item href="#usage" depth={1}>Usage</.toc_item>
</.toc>
</aside>The PhiaToc hook uses IntersectionObserver to set data-toc-active on the currently visible section's link.
back_to_top
Scroll-to-top button that appears after scrolling past a threshold. Hook: PhiaBackTop.
<.back_to_top id="back-btn" threshold={400} />page_progress
Thin progress bar at the top of the page showing scroll position. Hook: PhiaPageProgress.
<.page_progress id="read-progress" class="fixed top-0 left-0 z-50" />link_group
Grouped set of links with an optional heading — common in footers and sidebars.
<.link_group>
<.link_group_heading>Product</.link_group_heading>
<.link_group_item href="/features">Features</.link_group_item>
<.link_group_item href="/pricing">Pricing</.link_group_item>
<.link_group_item href="/changelog">Changelog</.link_group_item>
</.link_group>context_nav
Contextual sidebar navigation for settings-style pages.
<div class="flex gap-8">
<aside class="w-56 shrink-0">
<.context_nav>
<.context_nav_item href="/settings/profile" active={@section == :profile}>
Profile
</.context_nav_item>
<.context_nav_item href="/settings/security" active={@section == :security}>
Security
</.context_nav_item>
<.context_nav_item href="/settings/billing" active={@section == :billing}>
Billing
</.context_nav_item>
</.context_nav>
</aside>
<main class="flex-1"><%= @inner_content %></main>
</div>nav_rail
Compact vertical icon navigation (Material-style).
<.nav_rail>
<.nav_rail_item icon="home" href="/" label="Home" active={@active == :home} />
<.nav_rail_item icon="search" href="/search" label="Search" active={@active == :search} />
<.nav_rail_item icon="bell" href="/notifications" label="Alerts" badge={@unread} />
<.nav_rail_item icon="settings" href="/settings" label="Settings" />
</.nav_rail>bottom_navigation
Mobile bottom tab bar (iOS/Android style).
<.bottom_navigation active={@tab} on_change="set_tab">
<:item value="home" icon="home" label="Home" />
<:item value="search" icon="search" label="Search" />
<:item value="inbox" icon="inbox" label="Inbox" badge={@unread} />
<:item value="profile" icon="user" label="Profile" />
</.bottom_navigation>chip_nav
Horizontally scrollable filter chip navigation row.
<.chip_nav active={@category} on_change="set_category">
<:item value="all">All</:item>
<:item value="design">Design</:item>
<:item value="engineering">Engineering</:item>
<:item value="product">Product</:item>
</.chip_nav>floating_nav
Floating pill navigation bar — centered at the bottom of the viewport.
<.floating_nav active={@page}>
<.floating_nav_item href="/" icon="home" label="Home" />
<.floating_nav_item href="/explore" icon="compass" label="Explore" />
<.floating_nav_item href="/create" icon="plus-circle" label="Create" />
<.floating_nav_item href="/profile" icon="user" label="Profile" />
</.floating_nav>speed_dial
Floating action button that expands into multiple options.
<.speed_dial icon="plus" position={:bottom_right} label="New">
<:action icon="file-text" phx-click="new_doc" label="Document" />
<:action icon="image" phx-click="new_image" label="Image" />
<:action icon="folder" phx-click="new_folder" label="Folder" />
</.speed_dial>