cnc-tabs
One tab strip with four looks. Each tab is a
<template>
child carrying its label, icon and content — or an
href, in which case the panel is a block loaded in its place. Tabs can be closed,
pinned, disabled, hidden or dropped before render, the strip can occupy any of twelve perimeter
placements, and the active tab submits as a form field.
kind, size, color, shape and
placement
are read straight off the tag. Placement also determines ARIA orientation, keyboard navigation,
and the overflow axis while all four presentations share the same events.
Quick start
One <template> per tab. label is the text on the strip and the
template's content is the panel. value names the tab that opens first; without one
the first enabled tab wins.
<cnc-tabs value="dashboard">
<template name="dashboard" label="Dashboard" icon="material-symbols/dashboard">
<div>The dashboard panel.</div>
</template>
<template name="profile" label="Profile" icon="ph/user-fill">
<div>The profile panel.</div>
</template>
</cnc-tabs>
Tab attributes
Each <template> carries its own configuration. Only the label is really
needed; the rest opt into behaviour.
| Attribute | Purpose |
|---|---|
| name |
The tab's identity, used by value, closed and every event.
OPTIONAL: a template without one is named tab1, tab2 by
position.
|
| label | The text on the strip. |
| icon | A cnc-icon name shown before the label. |
| href | Loads the panel as a block from this URL. The template's own children are ignored when it is set. |
| closable | Adds a close button, and lets Delete close the tab from the keyboard. |
| pinnable |
Adds a pin toggle. The widget holds the pinned flag for the session only —
persisting it is the host's job, which is what the pin event is for.
|
| disabled | Renders greyed out and cannot be selected, by click or by arrow key. A disabled tab is never chosen as the initial or post-close selection either. |
| hide="true" |
Leaves the tab out entirely at startup, like listing it in closed.
|
Keyboard
The strip is a tablist with roving focus: it is ONE tab stop, and the arrows walk
it from there. Selection follows focus, exactly as clicking does. Disabled tabs are skipped, and
the arrows wrap at both ends.
| Key | Action |
|---|---|
| Tab | Moves into the strip (landing on the active tab), then on to its pin/close controls, then out to the panel. |
| ← / → | Previous / next tab, on a horizontal strip. |
| ↑ / ↓ | Previous / next tab, on a left or right placement. |
| Home / End | First / last enabled tab. |
| Delete | Closes the active tab, if it is closable. |
Styling hooks
Every customisable value is a semantic variable, so an instance can be retuned without
overriding a selector. The public parts are
.cnc-tabs_nav, .cnc-tabs_list, .cnc-tabs_item,
.cnc-tabs_icon, .cnc-tabs_label, .cnc-tabs_pin,
.cnc-tabs_close, .cnc-tabs_scroll and
.cnc-tabs_panel.
<!-- retune one instance -->
<cnc-tabs style="--item-height: 3rem; --item-border-radius: 1rem; --panel-padding: 0">
<!-- or reach a part directly when a variable is not enough -->
<cnc-tabs class="[&_.cnc-tabs_label]:uppercase">
Common variables
--item-height --item-padding --item-gap
--item-bg --item-bg-hover --item-bg-selected
--item-text-color --item-text-color-hover --item-text-color-selected
--item-border-radius --indicator-size --indicator-color-selected
--list-gap --list-bg --list-border-color
--list-shadow-gutter (increase for larger custom tab shadows)
--icon-size --control-size
--panel-padding --panel-bg --panel-border-color
Usage guidance
line
reads as page navigation and is the safe default. soft is the quietest and sits
well inside a card. filled reads as a control and suits switching a view in place.
curved
is the browser/editor strip — use it when tabs are documents the user opens and closes,
not sections of one page. Give every tab an explicit
name
as soon as anything refers to one, and fill empty-group whenever tabs are closable.
Migrating:
cnc-tabs-highlight
is now kind="soft",
cnc-tabs-button
is kind="filled", and
cnc-tabs-curved
is kind="curved". The tab attributes, slots and events are unchanged. Two
behaviours were fixed in the merge: closing the active tab now moves to its neighbour rather
than jumping to the first tab, and a disabled first tab is no longer selected at startup.