@k4k3ru/components-tab
v1.1.0
Published
Utility for tab component
Readme
Tab
Reusable framework-independent tabs. Use the default underline presentation or
tab__container--segmented; both share the existing design tokens, icon/badge
parts and compact sizing. No runtime dependency is required.
Page navigation
For different URLs, use native links inside a labelled nav. Set
aria-current="page" on the current link. No JavaScript, role="tab",
aria-selected, or roving tabindex is needed. Browser navigation, modifier-clicks,
back/forward and application departure guards remain native.
<nav class="tab__container tab__container--scrollable" aria-label="Market views">
<div class="tab__list">
<a class="tab" href="/snapshot/" aria-current="page">
<span class="tab__label">Snapshot</span>
<span class="tab__indicator" aria-hidden="true"></span>
</a>
<a class="tab" href="/live/">
<span class="tab__label">Live</span>
<span class="tab__indicator" aria-hidden="true"></span>
</a>
</div>
</nav>In-page panels
import { Tab } from '@k4k3ru/components-tab';
import '@k4k3ru/components-tab/dist/style.css';
const tabs = new Tab();
tabs.Run(); // Or Run(element) for a scoped view.
// On view disposal:
tabs.Destroy();<div class="tab__container">
<div class="tab__list" role="tablist" aria-label="Quote views">
<button class="tab" type="button" role="tab" aria-selected="true"
data-tab-target="quote"><span class="tab__label">Quote</span>
<span class="tab__indicator" aria-hidden="true"></span></button>
<button class="tab" type="button" role="tab" aria-selected="false"
data-tab-target="sources"><span class="tab__label">Sources</span>
<span class="tab__indicator" aria-hidden="true"></span></button>
</div>
</div>
<div class="tab__panels">
<section class="tab__panel" data-tab-id="quote">Current quote</section>
<section class="tab__panel" data-tab-id="sources" hidden>Quote sources</section>
</div>- Panel wrapper must be a direct child of the container or its immediate next
sibling. Each tab targets a distinct panel using
aria-controls/ panelid, or the existingdata-tab-target/data-tab-idattributes. Invalid groups are left untouched. No document-wide panel fallback is used. - Initialization assigns missing unique IDs, roles, panel labels, controls and selected state without moving focus. Existing IDs are retained.
- Arrow keys move focus and skip disabled tabs; Enter/Space activates the focused button. Home/End moves to the first/last enabled tab. Tab leaves the list. Manual activation avoids starting work merely by moving keyboard focus.
- Set
aria-orientation="vertical"on the list for Up/Down keys and a vertical layout. Horizontal keys follow RTL direction. Existingtab--verticalmeans icon above label, and is independent of list orientation. - Use native
disabledoraria-disabled="true"on panel buttons. Navigation links should be omitted when unavailable; do not putaria-disabledon a live href and expect CSS to prevent navigation. Run()is idempotent across instances.Destroy()releases owned handlers and permits reinitialization; it retains the current DOM state.tab__container--scrollablekeeps long lists within the viewport. Focus rings stay inside the control. Reduced-motion and forced-colors modes are supported.
Smaller size
Use tab--smaller on a tab or tab__container--smaller on the container for 32px
horizontal tabs, reduced padding and vertical icon size. Defaults remain 40px.
See shared sizing guidance.
Build and examples
Run npm run build:tab from the repository root. Open
example/index.html through a local HTTP server. The package
retains Tab, Run(), custom class options, and existing dist/* import paths.
Version 1.1.0 adds navigation styling, panel accessibility, scoped initialization,
keyboard handling, cleanup and TypeScript declarations.
References: shadcn/ui Tabs, Material 3 Tabs, Material Web Tabs, WAI-ARIA Tabs Pattern. The supplied Downloads/tab files informed the existing class and indicator design.
