Skip to content

Tabs

In review
Live · web

Underline tabs: icons + a count badge; the underline slides, the panel swaps (Tab in, Arrow keys)

Overview
Status, model, and recent summary

Enclosed tabs: the sliding cyan underline, seated inside a recessed well (not a filled pill)

Chat
The live session transcript

A disabled tab: skipped by arrow keys, still legible

Editor
Edit the document source

Scrollable / overflow: many tabs scroll horizontally with edge fades

Overview
The "Overview" section. Scroll the row and the underline follows

Small size: same indicator, tighter rhythm

Overview
Status, model, and recent summary

Active section: overview · enclosed chat · workspace overview. Each tab swaps its panel below. The island is live.

// Web: React, consuming @dizyx/nockerl-tokens. (Web is the laggard platform;
// this is the canonical API the published @dizyx/nockerl-react package exposes.)
import { NockerlTabs } from '@dizyx/nockerl-react';
export function SessionPanel() {
const [tab, setTab] = useState('overview');
return (
<NockerlTabs
label="Session sections"
value={tab}
onChange={setTab}
tabs={[
{ value: 'overview', label: 'Overview', icon: 'overview' },
{ value: 'activity', label: 'Activity', icon: 'activity' },
{ value: 'files', label: 'Files', icon: 'files', count: 12 },
{ value: 'settings', label: 'Settings', icon: 'settings', disabled: true },
]}
renderPanel={(v) => <SectionBody section={v} />}
/>
);
}
// Enclosed variant (the same cyan underline, inside a recessed well). Pass variant="enclosed".
<NockerlTabs label="Panel sections" variant="enclosed" value={tab} onChange={setTab} tabs={tabs} renderPanel={renderPanel} />
PropTypeDefaultDescription
tabs *TabItemDef[]The tabs, left-to-right. Each owns a panel rendered via renderPanel or its own panel.
value *stringThe active tab value (controlled). Exactly one tab is selected.
onChange(next: string) => voidFired with the next value. Ignored for a disabled tab.
label *stringAccessible name for the whole tablist (wired via aria-label).
variantNockerlTabsVariant'underline'Underline indicator (default) vs. 'enclosed': the same cyan underline seated inside a recessed well.
sizeNockerlTabsSize'md'Tab height + padding + type role.
renderPanel(value: string) => ReactNodeRenders the body for the active tab. Falls back to the tab's own panel.
onClose((value: string) => void) | undefinedCLOSABLE tabs (task 2656 dev-tab-bar): when set, every tab grows a trailing close affordance (pointer) and DELETE / BACKSPACE closes the focused tab (the keyboard half of the ARIA deletable-tabs pattern; the X itself stays out of the tab order). The list stays CONTROLLED: this only reports the value; the host removes the tab + moves selection.

Also accepts the native <div> attributes (e.g. onClick, disabled, id, aria-*, data-*), forwarded straight through, plus a forwarded ref.