HyTab
A tab component designed to work within a tab group to control associated tab panels. Provides keyboard navigation, accessibility features, and customizable styling. Supports both horizontal and vertical orientations and can include icons alongside text labels.
Hybrid SSR/CSR Icon Visibility System
The tab works seamlessly in both SSR and CSR-only (SPAs, Storybook) environments using a hybrid visibility approach:
In SSR environments:
- The host framework detects icon slot presence at render time via its own slot API
- Passes boolean attribute (
has-icon) to the Lit component - CSS uses this attribute for immediate icon wrapper visibility during initial render
- After hydration, HasSlotController confirms slot content and adds
.has-contentclass
In CSR-only environments (SPAs, Storybook):
- Icon wrapper renders to DOM (no
has-iconattribute) - Wrapper is hidden by default via CSS (
display: none) firstUpdated()runs andhideIconWrapperWithoutContent()detects actual content- Adds
.has-contentclass which triggers CSS visibility rules
This approach ensures consistent behavior across all rendering environments while optimizing for SSR performance and preventing layout shifts from flex gap.
Usage Guidelines
Tabs should be used within an hy-tab-group component for proper state management and keyboard navigation. Each tab controls a corresponding hy-tab-panel via the panel attribute.
Orientations
- horizontal (default): Tabs displayed in a row with bottom indicator
- vertical-left: Tabs displayed in a column with left-side indicator
- vertical-right: Tabs displayed in a column with right-side indicator
States
- default: Inactive tab state
- active: Selected tab that controls the visible panel
- disabled: Non-interactive tab state
Keyboard Navigation
When used within hy-tab-group:
- Arrow Right/Down: Move to next tab
- Arrow Left/Up: Move to previous tab
- Home: Move to first tab
- End: Move to last tab
- Enter/Space: Activate focused tab
Examples
Basic usage
<hy-tab-group>
<hy-tab slot="tab" label="Dashboard" panel="dashboard-panel"></hy-tab>
<hy-tab slot="tab" label="Settings" panel="settings-panel"></hy-tab>
<hy-tab-panel slot="panel" name="dashboard-panel"> Dashboard content </hy-tab-panel>
<hy-tab-panel slot="panel" name="settings-panel"> Settings content </hy-tab-panel>
</hy-tab-group>With active state
<hy-tab-group>
<hy-tab slot="tab" label="Overview" panel="overview-panel" active></hy-tab>
<hy-tab slot="tab" label="Analytics" panel="analytics-panel"></hy-tab>
<hy-tab slot="tab" label="Reports" panel="reports-panel"></hy-tab>
</hy-tab-group>With icons
<hy-tab-group>
<hy-tab slot="tab" label="Home" panel="home-panel">
<hy-icon slot="icon" name="home"></hy-icon>
</hy-tab>
<hy-tab slot="tab" label="Settings" panel="settings-panel">
<hy-icon slot="icon" name="settings"></hy-icon>
</hy-tab>
<hy-tab slot="tab" label="Profile" panel="profile-panel">
<hy-icon slot="icon" name="user"></hy-icon>
</hy-tab>
</hy-tab-group>Disabled tab
<hy-tab-group>
<hy-tab slot="tab" label="Available" panel="available-panel" active></hy-tab>
<hy-tab slot="tab" label="Premium" panel="premium-panel" disabled>
<hy-icon slot="icon" name="lock"></hy-icon>
</hy-tab>
</hy-tab-group>Vertical orientation with left indicator
<hy-tab-group orientation="vertical-left">
<hy-tab slot="tab" label="Profile" panel="profile-panel" orientation="vertical-left">
<hy-icon slot="icon" name="user"></hy-icon>
</hy-tab>
<hy-tab slot="tab" label="Security" panel="security-panel" orientation="vertical-left">
<hy-icon slot="icon" name="shield"></hy-icon>
</hy-tab>
<hy-tab slot="tab" label="Billing" panel="billing-panel" orientation="vertical-left">
<hy-icon slot="icon" name="credit-card"></hy-icon>
</hy-tab>
</hy-tab-group>Vertical orientation with right indicator
<hy-tab-group orientation="vertical-right">
<hy-tab slot="tab" label="Profile" panel="profile-panel" orientation="vertical-right">
<hy-icon slot="icon" name="user"></hy-icon>
</hy-tab>
<hy-tab slot="tab" label="Security" panel="security-panel" orientation="vertical-right">
<hy-icon slot="icon" name="shield"></hy-icon>
</hy-tab>
<hy-tab slot="tab" label="Billing" panel="billing-panel" orientation="vertical-right">
<hy-icon slot="icon" name="credit-card"></hy-icon>
</hy-tab>
</hy-tab-group>Complete tabbed interface
<div>
<hy-tab-group>
<hy-tab slot="tab" label="Home" panel="home-content" active>
<hy-icon slot="icon" name="home"></hy-icon>
</hy-tab>
<hy-tab slot="tab" label="Products" panel="products-content">
<hy-icon slot="icon" name="package"></hy-icon>
</hy-tab>
<hy-tab slot="tab" label="Support" panel="support-content">
<hy-icon slot="icon" name="help-circle"></hy-icon>
</hy-tab>
</hy-tab-group>
<hy-tab-panel name="home-content">
<h2>Welcome Home</h2>
<p>This is the home content area.</p>
</hy-tab-panel>
<hy-tab-panel name="products-content">
<h2>Our Products</h2>
<p>Browse our product catalog.</p>
</hy-tab-panel>
<hy-tab-panel name="support-content">
<h2>Support Center</h2>
<p>Get help and support.</p>
</hy-tab-panel>
</div>Programmatic Methods
const tab = document.querySelector('hy-tab');
// Set active state
tab.active = true;
// Focus the tab
tab.focus();
// Blur the tab
tab.blur();
// Check if disabled
console.log(tab.disabled);Events
- select - Fired when the tab is clicked or activated, includes panel ID and tab reference
Slots
- icon - Icon content to display before the tab label
Methods
focus()
Sets focus on the tab.
Parameters:
options- Optional focus options
const tab = document.querySelector('hy-tab');
tab.focus();blur()
Removes focus from the tab.
const tab = document.querySelector('hy-tab');
tab.blur();