Tabs
Implemented NavigationSegmented and underline tabs with a sliding indicator, responsive overflow and local Alpine or URL/HTMX state.
Kumo reference: kumo-ui.com/components/tabs/
Presentation commands show demo feedback. Read the interaction guide to connect real actions.
Variants (default)
Segmented (default)
Underline
Show template
{% load wdj %}
<div class="flex w-full flex-col items-center gap-6 py-2">
<div><p class="mb-2 text-base text-kumo-subtle">Segmented (default)</p>{% include "wdj/components/tabs.html" with id="default-segmented-tabs" items=demo_tab_items mode="local" only %}</div>
<div><p class="mb-2 text-base text-kumo-subtle">Underline</p>{% include "wdj/components/tabs.html" with id="default-underline-tabs" items=demo_tab_items mode="local" variant="underline" only %}</div>
</div>
Segmented
Show template
{% load wdj %}
{% include "wdj/components/tabs.html" with id="segmented-demo-tabs" items=demo_tab_items mode="local" only %}
Underline
Show template
{% load wdj %}
{% include "wdj/components/tabs.html" with id="underline-demo-tabs" items=demo_tab_items mode="local" variant="underline" only %}
Small
Segmented sm
Underline sm
Show template
{% load wdj %}
<div class="grid gap-6">
<div><p class="mb-2 text-base text-kumo-subtle">Segmented sm</p>{% include "wdj/components/tabs.html" with id="small-segmented-tabs" items=demo_tab_items mode="local" size="sm" only %}</div>
<div><p class="mb-2 text-base text-kumo-subtle">Underline sm</p>{% include "wdj/components/tabs.html" with id="small-underline-tabs" items=demo_tab_items mode="local" size="sm" variant="underline" only %}</div>
</div>
Controlled
Active tab: tab1
Show template
{% load wdj %}
<div class="grid gap-4" x-data="{ value: 'tab1' }" @wdj:tab-change="value = $event.detail.value">
<div x-ref="local">{% include "wdj/components/tabs.html" with id="controlled-demo-tabs" mode="local" items=demo_tab_items only %}</div>
<p class="text-base text-kumo-subtle">Active tab: <code data-tabs-value class="font-mono text-[0.9em]" x-text="value">tab1</code></p>
<div><button type="button" class="rounded-md bg-kumo-base px-2.5 py-1 text-base ring-1 ring-kumo-line hover:bg-kumo-tint" @click="$refs.local.querySelector('[data-wdj-tabs]').dispatchEvent(new CustomEvent('wdj:set-tab', { detail: { value: 'tab1' } }))">Reset selected tab</button></div>
</div>
Many tabs
Show template
{% load wdj %}
<div class="w-full max-w-md">{% include "wdj/components/tabs.html" with id="many-demo-tabs" mode="local" items=many_local_tabs only %}</div>
Horizontal overflow
Show template
{% load wdj %}
<div class="w-full max-w-xs">{% include "wdj/components/tabs.html" with id="overflow-demo-tabs" mode="local" items=many_local_tabs only %}</div>
Dynamic tab count
10 tabs
Show template
{% load wdj %}
<div class="grid min-w-0 gap-3" x-data="{ extra: true }">
<div x-ref="tabs" class="min-w-0 w-full max-w-[588px]">{% include "wdj/components/tabs.html" with id="dynamic-demo-tabs" mode="local" selected="settings" items=dynamic_local_tabs only %}</div>
<div class="flex flex-wrap items-center gap-3">
<button type="button" class="rounded-md bg-kumo-base px-2.5 py-1 text-base ring-1 ring-kumo-line hover:bg-kumo-tint" @click="extra = !extra; $refs.tabs.querySelectorAll('[data-tab-extra]').forEach(tab => tab.hidden = !extra)">Toggle extra tabs</button>
<span data-tabs-count class="text-base text-kumo-subtle" x-text="extra ? '10 tabs' : '7 tabs'">10 tabs</span>
</div>
</div>
Icons and badges
Show template
{% load wdj %}
{% include "wdj/components/tabs.html" with items=decorated_tabs only %}
Disabled tab
Show template
{% load wdj %}
{% include "wdj/components/tabs.html" with items=disabled_tabs only %}
HTMX content
Analytics
Inspect synthetic request and cache statistics.
Show template
{% load wdj %}
{% include "showcase/_tabs_example.html" %}
URL state
Current tab: analytics
Show template
{% load wdj %}
<div class="grid gap-3">{% include "wdj/components/tabs.html" with items=tab_items variant="underline" label="Current URL tabs" only %}<p class="text-base text-kumo-subtle">Current tab: {{ selected_tab }}</p></div>
Overflow
Show template
{% load wdj %}
{% include "wdj/components/tabs.html" with items=long_tabs class="w-full max-w-xs" only %}
External link
Show template
{% load wdj %}
{% include "wdj/components/tabs.html" with items=external_tabs only %}
Local panels (Alpine)
Show template
{% load wdj %}
{% include "wdj/components/tabs.html" with id="local-project-tabs" mode="local" items=local_tab_items label="Local project tabs" only %}
Local rich content
Local panels can contain any wdj control.
Show template
{% load wdj %}
{% wdj_component "wdj/components/tabs.html" id="rich-project-tabs" mode="local" variant="underline" items=local_tab_items label="Local settings tabs" %}
{% wdj_component "wdj/components/tab_panel.html" key="overview" %}<p>Local panels can contain any wdj control.</p>{% endwdj_component %}
{% wdj_component "wdj/components/tab_panel.html" key="settings" %}
{% include "wdj/components/switch.html" with name="tabs_notifications" label="Notifications" checked=True only %}
{% endwdj_component %}
{% include "wdj/components/tab_panel.html" with key="disabled" text="This panel cannot be selected." only %}
{% endwdj_component %}
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| items | list[dict] | [] | Local: key/label/content?/disabled?/icon?/badge?/attrs?. Navigation: label/href/active?/disabled?/hx_get?/hx_target?. |
| mode | navigation | local | navigation | Real URL/HTMX links or local Alpine tab buttons and panels. |
| variant | segmented | underline | segmented | Filled track with a sliding pill, or a moving underline. |
| size | base | sm | base | Segmented: 36/26px. Underline: 30/26px. Text: 14/12px. |
| id | string | generated | Unique local root ID; tab/panel IDs derive from it. |
| selected | string | first enabled | Initial local item key; navigation selection comes from items[].active. |
| activate_on_focus | bool | False | Local mode: activate on focus instead of requiring Enter/Space. |
| label | string | Tabs | Accessible label for the navigation or local tablist. |
| scroll_start_label / scroll_end_label | string | Scroll tabs left / right | Localized accessible names for segmented overflow controls. |
| class | string | Additional literal root classes; width is constrained by the parent. |