Tab Nav

Responsive routed tab navigation for LiveView pages.

Unlike the full tabs component which manages content panels client-side, Tab Nav renders route links. It replaces the old Nav Pills component and collapses to a mobile dropdown by default.

Default

Usage

Tab Nav uses patch for LiveView navigation, keeping the socket connection alive. Use collapse="never" only when the tab row should stay visible on small screens.

Usage
# In your LiveView
def mount(%{"id" => id}, _session, socket) do
  {:ok, assign(socket, org: get_org(id), active_tab: :about)}
end

# In the template
<.tab_nav id="org-tabs">
  <:tab patch={~p"/orgs/#{@org.id}"} active={@active_tab == :about}>
    About
  </:tab>
  <:tab patch={~p"/orgs/#{@org.id}/members"} active={@active_tab == :members}>
    Members
  </:tab>
</.tab_nav>

# Optional: keep tabs visible on small screens
<.tab_nav id="settings-tabs" collapse="never">
  <:tab patch={~p"/settings"} active={@active_tab == :profile}>
    Profile
  </:tab>
  <:tab patch={~p"/settings/billing"} active={@active_tab == :billing}>
    Billing
  </:tab>
</.tab_nav>

With Icons

Include icons alongside text in the tab inner block.

With Icons

When to Use

Tab Nav is ideal for scenarios where:

  • Each tab loads different data from the server
  • Tab content is heavy (analytics, tables, charts)
  • You want separate URLs for each tab for bookmarking
  • Content should only load when the tab is active

For client-side tab switching with all content loaded upfront, use the Tabs component instead.

Accessibility

Tab Nav uses navigation semantics with aria-current for the active route. For in-page tab panels with role="tablist" and role="tabpanel" use the Tabs component.