Prototype Library

Tab Layout

An ARIA tablist with active-tab state, roving keyboard navigation (Arrow / Home / End, skipping disabled tabs), badges, and a swapping panel. A Lit web component.

Inherited wc import '@esa/ecology/esa-tab-layout';

Preview

Overview content — summary metrics and status.
Activity content — recent events log.
Settings content — configuration form.
<esa-tab-layout id="tabs">
  <div slot="panel-0">Overview content — summary metrics and status.</div>
  <div slot="panel-1">Activity content — recent events log.</div>
  <div slot="panel-2">Settings content — configuration form.</div>
</esa-tab-layout>

<script>
  document.getElementById('tabs').tabs = [
    { label: 'Overview' }, { label: 'Activity' }, { label: 'Settings' },
  ];
</script>

Appearance

Two appearances, aligned to Beacon's UiTabsAppearance. underline (default) shows an underlined indicator on the active tab; segmented renders a segmented control — a sunken, bordered track with a filled selected segment and no indicator. (variant="pill" is the legacy alias for segmented.)

Underline appearance.
Second panel.
Third panel.
Segmented appearance.
Second panel.
Third panel.
<esa-tab-layout appearance="underline"></esa-tab-layout>
<esa-tab-layout appearance="segmented"></esa-tab-layout>

Sizes

Extra small.
Two.
Small.
Two.
Medium.
Two.
Large.
Two.
<esa-tab-layout size="xs"></esa-tab-layout>
<esa-tab-layout size="sm"></esa-tab-layout>
<esa-tab-layout size="md"></esa-tab-layout>
<esa-tab-layout size="lg"></esa-tab-layout>

States

Tabs accept badges, and any tab can be disabled — keyboard navigation skips disabled tabs.

Inbox.
Archive (tab 2 is disabled).
<script>
  el.tabs = [
    { label: 'Inbox', badge: 4 },
    { label: 'Drafts', disabled: true },
    { label: 'Archive', badge: 128 },
  ];
</script>

API

PropTypeDefaultDescription
tabs EsaTab[] [] Tab definitions (property, set via JS). Each is { label; icon?; badge?; disabled? }.
active-index number 0 Index of the selected tab.
size 'xs' | 'sm' | 'md' | 'lg' 'md' Tab height and type scale. Reflected as an attribute.
appearance 'underline' | 'segmented' 'underline' Tab style (aligned to Beacon): underlined indicator or a segmented control on a sunken track. Reflected as an attribute.
variant 'underline' | 'pill' 'underline' Legacy alias for appearance — pill maps to segmented. Prefer appearance.

Events

EventTypeDefaultDescription
tabchange CustomEvent Fired when the active tab changes. detail: { index: number }. Bubbles and composed.

tabs is an array property — set it in JS, not as an attribute. Each EsaTab.icon is a raw inline SVG string.

Slots

PropTypeDefaultDescription
panel-{index} slot Content for the matching tab; the active panel is shown. Falls back to the default slot.

The routed-tabs (RouterOutlet) branch of the Angular component is replaced here by content panels via the named slots above.

Accessibility

  • Follows the ARIA tablist pattern: role="tablist" / role="tab" / role="tabpanel" with aria-selected.
  • Roving tabindex — only the active tab is in the tab order; ArrowLeft / ArrowRight / Home / End move focus and selection, skipping disabled tabs.
  • Disabled tabs are non-interactive and excluded from keyboard traversal.