0.1.0

Tabs

Tabs organize related content into panels where only one is visible at a time, such as settings sections, product details, or dashboards.

Try it

Account settings
Security settings

Usage

Compose RuiTabList, RuiTab, RuiTabPanels, and RuiTabPanel. Set value to control the active tab.

import { RuiTabs, RuiTabList, RuiTab, RuiTabPanels, RuiTabPanel } from '@ecopages/radiant-ui/tabs';
 
<RuiTabs value="account" variant="boxed">
  <RuiTabList>
    <RuiTab id="account">Account</RuiTab>
    <RuiTab id="security">Security</RuiTab>
  </RuiTabList>
  <RuiTabPanels>
    <RuiTabPanel id="account">Account settings</RuiTabPanel>
    <RuiTabPanel id="security">Security settings</RuiTabPanel>
  </RuiTabPanels>
</RuiTabs>

Custom markup

<rui-tabs> coordinates any light-DOM tree that matches its query contract. The Rui* helpers stamp these targets; they are not required.

import '@ecopages/radiant-ui/tabs';
 
<rui-tabs value="account">
  <div role="tablist" aria-label="Settings">
    <button type="button" role="tab" id="tab-account" data-tab-value="account" aria-controls="panel-account">
      Account
    </button>
    <button type="button" role="tab" id="tab-security" data-tab-value="security" aria-controls="panel-security">
      Security
    </button>
  </div>
  <div role="tabpanel" id="panel-account" data-tab-value="account" aria-labelledby="tab-account">
    Account settings
  </div>
  <div role="tabpanel" id="panel-security" data-tab-value="security" aria-labelledby="tab-security" hidden>
    Security settings
  </div>
</rui-tabs>;

Boxed or ghost

boxed tabs have a contained background and work well in settings panels. ghost tabs sit flush with the page header.

Account settings
Security settings

Manual activation

Set automatic=\{false} when switching tabs should require an explicit Enter/Space press.

Account settings
Security settings

Theming

Tabs map to semantic surface + primary roles, never Tailwind palette steps. Override --rui-tabs-* on rui-tabs. Variants (boxed / ghost) stay; they set layout recipes, not a parallel color API.

Part / variantDefaultOverride
Tab texton-backgroundtheme
Active indicator2px --primary--rui-tabs-indicator-width, --rui-tabs-indicator-color
Tab padding--space-control-x / --space-control-y--rui-tabs-tab-padding-x, --rui-tabs-tab-padding-y
Boxed card--background + --border + --rui-tabs-radius--rui-tabs-radius
Boxed tab stripsurface-container-lowtheme
Panels--space-inset--rui-tabs-panel-padding
Focusfocus-ring at reduced alphatheme
rui-tabs {
  --rui-tabs-indicator-color: var(--secondary);
  --rui-tabs-panel-padding: var(--space-2);
}

Accessibility

  • Tab list exposes role="tablist" with aria-selected on the active tab.
  • Arrow keys move between tabs; activation follows the automatic setting.
  • Each panel is labelled by its corresponding tab via aria-labelledby.

API

RuiTabs is a custom element (<rui-tabs>) coordinating role="tablist" / role="tab" / role="tabpanel" markup authored via the view helpers.

Attributes (<rui-tabs>)

AttributeTypeDefaultDescription
variantghost ยท boxedboxedVisual treatment.
valuestring''Selected tab id; defaults to the first tab.
labelstring''Accessible name for the tab list (prefer aria-label on RuiTabList).
automaticbooleantrueAutomatic (focus activates) vs manual (Enter/Space) activation.

Light-DOM contract

TargetRequiredHost writesAuthor owns
[role="tablist"]yesaria-label (from label when absent)aria-label (preferred)
[role="tab"]yesaria-selected, tabIndexdata-tab-value or id, aria-disabled
[role="tabpanel"]yeshidden, tabIndex when unsetdata-tab-value or id

Do not set aria-selected, tabIndex, or hidden after connect โ€” the host owns those via resync(). Nested hosts: none.

Events

EventDetailDescription
rui-change{ value: string }Emitted when the selected tab changes.

Methods

MethodDescription
resync()Re-applies tablist labeling and selected/hidden state from value.

View helpers

ComponentTarget stampedNotes
RuiTabList[role="tablist"]Set aria-label here when possible.
RuiTab[role="tab"], data-tab-value, id="tab-{id}"Pairs with RuiTabPanel by id.
RuiTabPanelsโ€”Presentation wrapper only.
RuiTabPanel[role="tabpanel"], data-tab-value, id="panel-{id}"Hidden when not selected.

CSS classes

Public BEM classes (documented via @cssclass):

ClassDescription
.rui-tabs__listrole="tablist" strip.
.rui-tabs__tabrole="tab" button; underline/border per variant.
.rui-tabs__panelsPanel group.
.rui-tabs__panelrole="tabpanel"; hidden when not selected.

Theme roles

PartCSS variables consumed
Active indicator--primary
Focus ring--focus-ring
Boxed card / panels--background, --border, --surface-container-low, --shadow-sm, --radius-container, --p-inset