Tabs
Summary
Tabbed navigation between sibling content panels. Two
orientations (horizontal, vertical) and a disabled modifier
for read-only step indicators. Tab switching is auto-bound on
DOMContentLoaded; no JS is required for static
markup.
When to use
| Variant | Use it for |
|---|---|
Horizontal.neura-tabs-horizontal | Top-level page sections: Overview / Details / History on a record page. |
Vertical.neura-tabs-vertical | Settings sub-navigation: Profile / Account / Notifications. Better when the menu has 4+ items. |
Disabled.neura-tabs-disabled | Read-only step indicator (e.g. wizard breadcrumbs). Clicks are ignored. |
Examples
Click any tab to switch panes. Horizontal and vertical orientations behave identically; the disabled variant ignores clicks for read-only step indicators.
Horizontal tabs
First panel. Use arrow keys on the focused tab to switch via keyboard.
Second panel.
Third panel.
Vertical tabs
Profile settings - your display name, avatar, and bio.
Account settings - email, password, and connected services.
Notification preferences - email, push, in-app.
Security - two-factor authentication, sessions, API keys.
Disabled tabs
Disabled tabs - clicks are ignored. Used when tabs are read-only or sequential.
Step 2 content (unreachable while disabled).
Step 3 content (unreachable while disabled).
HTML
Markup contract: a .neura-tabs-menu with one
.neura-tabs-menu-item per tab, followed by one
.neura-tabs-pane per item. Each link's
href matches the pane's id. Mark the
initially-active tab with .active-tab and the
matching pane with .active-pane.
<div class="neura-tabs neura-tabs-horizontal">
<ul class="neura-tabs-menu">
<li class="neura-tabs-menu-item active-tab">
<a href="#h-tab-1"><strong>Overview</strong></a>
</li>
<li class="neura-tabs-menu-item">
<a href="#h-tab-2"><strong>Details</strong></a>
</li>
<li class="neura-tabs-menu-item">
<a href="#h-tab-3"><strong>History</strong></a>
</li>
</ul>
<div id="h-tab-1" class="neura-tabs-pane active-pane">
<p>First panel. Use arrow keys on the focused tab to switch via keyboard.</p>
</div>
<div id="h-tab-2" class="neura-tabs-pane">
<p>Second panel.</p>
</div>
<div id="h-tab-3" class="neura-tabs-pane">
<p>Third panel.</p>
</div>
</div>
Vertical orientation changes only the modifier class:
<div class="neura-tabs neura-tabs-vertical">
<ul class="neura-tabs-menu">
<li class="neura-tabs-menu-item active-tab">
<a href="#v-tab-1"><strong>Profile</strong></a>
</li>
<li class="neura-tabs-menu-item">
<a href="#v-tab-2"><strong>Account</strong></a>
</li>
<li class="neura-tabs-menu-item">
<a href="#v-tab-3"><strong>Notifications</strong></a>
</li>
<li class="neura-tabs-menu-item">
<a href="#v-tab-4"><strong>Security</strong></a>
</li>
</ul>
<div id="v-tab-1" class="neura-tabs-pane active-pane">
<p>Profile settings - your display name, avatar, and bio.</p>
</div>
<div id="v-tab-2" class="neura-tabs-pane">
<p>Account settings - email, password, and connected services.</p>
</div>
<div id="v-tab-3" class="neura-tabs-pane">
<p>Notification preferences - email, push, in-app.</p>
</div>
<div id="v-tab-4" class="neura-tabs-pane">
<p>Security - two-factor authentication, sessions, API keys.</p>
</div>
</div>
To make tabs read-only / disabled, add .neura-tabs-disabled on the root:
<div class="neura-tabs neura-tabs-horizontal neura-tabs-disabled">
<ul class="neura-tabs-menu">
<li class="neura-tabs-menu-item active-tab">
<a href="#d-tab-1"><strong>Step 1</strong></a>
</li>
<li class="neura-tabs-menu-item">
<a href="#d-tab-2"><strong>Step 2</strong></a>
</li>
<li class="neura-tabs-menu-item">
<a href="#d-tab-3"><strong>Step 3</strong></a>
</li>
</ul>
<div id="d-tab-1" class="neura-tabs-pane active-pane">
<p>Disabled tabs - clicks are ignored. Used when tabs are read-only or sequential.</p>
</div>
<div id="d-tab-2" class="neura-tabs-pane">
<p>Step 2 content (unreachable while disabled).</p>
</div>
<div id="d-tab-3" class="neura-tabs-pane">
<p>Step 3 content (unreachable while disabled).</p>
</div>
</div>
CSS classes
| Class | Effect |
|---|---|
.neura-tabs | Root. Required. |
.neura-tabs-horizontal | Tab strip on top, pane below. |
.neura-tabs-vertical | Tab list on left, pane on right. |
.neura-tabs-disabled | Modifier: clicks are ignored, cursor stays default. |
.neura-tabs-menu | The <ul> wrapping the tab items. |
.neura-tabs-menu-item | Each <li> in the menu. |
.neura-tabs-pane | Each panel that the tabs reveal. |
.active-tab | Marks the currently-selected tab item. |
.active-pane | Marks the currently-visible pane. |
Keyboard
The tab strip uses a roving tabindex: only the active tab is in the Tab order. On a focused tab, ArrowRight / ArrowDown move to the next tab and ArrowLeft / ArrowUp to the previous one (wrapping); Home and End jump to the first / last tab. Moving activates the tab and focuses it. Horizontal arrows follow visual direction: in RTL, ArrowLeft means next.
JavaScript
Tabs auto-init on DOMContentLoaded; for static
markup you don't need to write any JS. Use the API only when
you want to switch tabs imperatively or react to switches.
API
| Member | Description |
|---|---|
Neura.tabs(rootOrSelector) | Get the singleton instance for a .neura-tabs root. |
.activate(tabAnchor) | Switch to a tab by its anchor element (<a> inside the menu item). |
.activateById(paneId) | Switch to a tab by its pane's id. |
.on('change', fn) | Fires after a tab switch. fn receives the CustomEvent with detail: { tab, pane } (the tab anchor and the pane element). The event also bubbles from the root as neura-tabs-change. |
.off('change', fn) | Unsubscribe. |
Switch a tab imperatively (clicking the underlying link works too):
// By pane id…
Neura.tabs('#account-tabs').activateById('tab-2');
// …or by anchor element (or just click the link)
document.querySelector('.neura-tabs a[href="#tab-2"]').click();
React to tab switches (e.g. update the URL, lazy-load content):
Neura.tabs('#account-tabs').on('change', (e) => {
history.replaceState(null, '', '#' + e.detail.pane.id);
// or fetch and inject content into e.detail.pane, the pane just shown
});
AUI compatibility
.aui-tabs, .aui-tabs-horizontal,
.aui-tabs-vertical, .aui-tabs-disabled,
and the menu / pane / active-* selectors all alias to the
Neura rules. AJS.tabs.setup() and
AJS.tabs.change(tabAnchor) are wired through the shim.
Existing Velocity templates render unchanged.