Components
Tabs
Tabs
Three styles: segmented (a raised pill on a muted track), underline, and pill. Tabs are links or buttons - wire them to live_patch, JS commands or events.
Three styles
segmented is the modern default for in-page switching - the active tab is a raised pill on a muted track, nested-radius; underline suits page-level navigation; pill is the roomy classic. Tabs are links or buttons via link_type - wire them to live_patch, JS commands or events; number renders the count badge.
<div class="flex flex-col items-center gap-8">
<.tabs variant="segmented">
<.tab variant="segmented" is_active link_type="button">Overview</.tab>
<.tab variant="segmented" link_type="button">Analytics</.tab>
<.tab variant="segmented" link_type="button" number={4}>Reports</.tab>
</.tabs>
<.tabs variant="underline">
<.tab variant="underline" is_active link_type="button">Overview</.tab>
<.tab variant="underline" link_type="button">Analytics</.tab>
<.tab variant="underline" link_type="button" number={4}>Reports</.tab>
</.tabs>
<.tabs variant="pill">
<.tab variant="pill" is_active link_type="button">Overview</.tab>
<.tab variant="pill" link_type="button">Analytics</.tab>
<.tab variant="pill" link_type="button" number={4}>Reports</.tab>
</.tabs>
</div>
With icons
Anything goes in the tab body - icons beside labels here. The legacy underline flag still works; variant wins when both are set.
<.tabs variant="segmented">
<.tab variant="segmented" is_active link_type="button">
<.icon name="hero-chart-bar" class="w-4 h-4 mr-1.5" /> Dashboard
</.tab>
<.tab variant="segmented" link_type="button">
<.icon name="hero-users" class="w-4 h-4 mr-1.5" /> Team
</.tab>
<.tab variant="segmented" link_type="button">
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1.5" /> Settings
</.tab>
</.tabs>
Properties
<.tabs>
| Attribute | Type | Default | Description |
|---|---|---|---|
class
|
any |
nil
|
CSS class |
rest
|
global |
||
underline
|
boolean |
false
|
underlines your tabs (legacy for variant="underline") |
variant
|
string |
nil
|
tab style: pill (default), underline, or segmented - active tab is a raised white pill on a muted track. Overrides the legacy underline flag
one of: nil, "pill", "underline", "segmented"
|
:inner_block
slot
|
slot |
<.tab>
| Attribute | Type | Default | Description |
|---|---|---|---|
class
|
any |
nil
|
CSS class |
disabled
|
boolean |
false
|
disables your tab |
is_active
|
boolean |
false
|
indicates the current tab |
label
|
string |
nil
|
labels your tab |
link_type
|
string |
"a"
|
button renders a real <button type="button"> for phx-click / JS-command tabs - no href, and no implicit submit inside forms
one of: "a", "live_patch", "live_redirect", "button"
|
number
|
integer |
nil
|
indicates a number next to your tab |
on_change
|
{:struct, Phoenix.LiveView.JS} |
%Phoenix.LiveView.JS{ops: []}
|
JS commands to run when this tab is selected |
rest
|
global |
||
to
|
string |
nil
|
link path |
underline
|
boolean |
false
|
underlines your tab (legacy for variant="underline") |
variant
|
string |
nil
|
match the parent tabs variant. Overrides the legacy underline flag
one of: nil, "pill", "underline", "segmented"
|
:inner_block
slot
|
slot |