AvesraAvesrabeta

Tabs

Tabs organize content into multiple sections and allow users to navigate between them.

Import

import { AvTabsImports } from '@avesra/angular';

Usage

View your project overview and recent activity.

import { Component } from '@angular/core';
import { AvTabsImports } from '@avesra/angular';

@Component({
  selector: 'app-tabs-basic-demo',
  imports: [AvTabsImports],
  template: `
<av-tabs class="w-full max-w-md" default-selected-key="overview">
  <div av-tabs-list-container>
    <div av-tabs-list aria-label="Options">
      <span av-tabs-indicator></span>
      <button av-tabs-tab id="overview">Overview</button>
      <button av-tabs-tab id="analytics">Analytics</button>
      <button av-tabs-tab id="reports">Reports</button>
    </div>
  </div>
  <div class="pt-4" av-tabs-panel id="overview">
    <p>View your project overview and recent activity.</p>
  </div>
  <div class="pt-4" av-tabs-panel id="analytics">
    <p>Track your metrics and analyze performance data.</p>
  </div>
  <div class="pt-4" av-tabs-panel id="reports">
    <p>Generate and download detailed reports.</p>
  </div>
</av-tabs>
`,
})
export class TabsBasicDemo {}

Anatomy

Import the Tabs parts and compose them. Place a single span[av-tabs-indicator] inside the list (Material ink-bar). Optional span[av-tabs-separator] goes inside each tab except the first.

<av-tabs>
  <div av-tabs-list-container>
    <div av-tabs-list aria-label="Options">
      <span av-tabs-indicator></span>
      <button av-tabs-tab id="tab-1">Tab 1</button>
      <button av-tabs-tab id="tab-2">
        <span av-tabs-separator></span> <!-- Optional -->
        Tab 2
      </button>
    </div>
  </div>
  <div av-tabs-panel id="tab-1"></div>
  <div av-tabs-panel id="tab-2"></div>
</av-tabs>

Vertical

Account Settings

Manage your account information and preferences.

import { Component } from '@angular/core';
import { AvTabsImports } from '@avesra/angular';

@Component({
  selector: 'app-tabs-vertical-demo',
  imports: [AvTabsImports],
  template: `
<av-tabs class="w-full max-w-lg" orientation="vertical" default-selected-key="account">
  <div av-tabs-list-container>
    <div av-tabs-list aria-label="Vertical tabs">
      <span av-tabs-indicator></span>
      <button av-tabs-tab id="account">Account</button>
      <button av-tabs-tab id="security">Security</button>
      <button av-tabs-tab id="notifications">Notifications</button>
      <button av-tabs-tab id="billing">Billing</button>
    </div>
  </div>
  <div class="px-4" av-tabs-panel id="account">
    <h3 class="mb-2 font-semibold">Account Settings</h3>
    <p class="text-sm text-muted">Manage your account information and preferences.</p>
  </div>
  <div class="px-4" av-tabs-panel id="security">
    <h3 class="mb-2 font-semibold">Security Settings</h3>
    <p class="text-sm text-muted">
      Configure two-factor authentication and password settings.
    </p>
  </div>
  <div class="px-4" av-tabs-panel id="notifications">
    <h3 class="mb-2 font-semibold">Notification Preferences</h3>
    <p class="text-sm text-muted">Choose how and when you want to receive notifications.</p>
  </div>
  <div class="px-4" av-tabs-panel id="billing">
    <h3 class="mb-2 font-semibold">Billing Information</h3>
    <p class="text-sm text-muted">View and manage your subscription and payment methods.</p>
  </div>
</av-tabs>
`,
})
export class TabsVerticalDemo {}

Overflow

When the tab list exceeds the available space, div[av-tabs-list-container] automatically renders scroll chevrons and fading edges so users can navigate the hidden tabs. This works the same way for both horizontal and vertical orientations.

Overview panel content.

import { Component } from '@angular/core';
import { AvTabsImports } from '@avesra/angular';

@Component({
  selector: 'app-tabs-overflow-demo',
  imports: [AvTabsImports],
  template: `
<av-tabs class="w-[400px]" default-selected-key="overview">
  <div av-tabs-list-container>
    <div av-tabs-list aria-label="Overflow options">
      <span av-tabs-indicator></span>
      <button av-tabs-tab id="overview">Overview</button>
      <button av-tabs-tab id="analytics">Analytics</button>
      <button av-tabs-tab id="reports">Reports</button>
      <button av-tabs-tab id="performance">Performance</button>
      <button av-tabs-tab id="engagement">Engagement</button>
      <button av-tabs-tab id="audience">Audience</button>
      <button av-tabs-tab id="acquisition">Acquisition</button>
      <button av-tabs-tab id="retention">Retention</button>
      <button av-tabs-tab id="settings">Settings</button>
    </div>
  </div>
  <div av-tabs-panel id="overview"><p>Overview panel content.</p></div>
  <div av-tabs-panel id="analytics"><p>Analytics panel content.</p></div>
  <div av-tabs-panel id="reports"><p>Reports panel content.</p></div>
  <div av-tabs-panel id="performance"><p>Performance panel content.</p></div>
  <div av-tabs-panel id="engagement"><p>Engagement panel content.</p></div>
  <div av-tabs-panel id="audience"><p>Audience panel content.</p></div>
  <div av-tabs-panel id="acquisition"><p>Acquisition panel content.</p></div>
  <div av-tabs-panel id="retention"><p>Retention panel content.</p></div>
  <div av-tabs-panel id="settings"><p>Settings panel content.</p></div>
</av-tabs>
`,
})
export class TabsOverflowDemo {}

Disabled Tab

This tab is active and can be selected.

import { Component } from '@angular/core';
import { AvTabsImports } from '@avesra/angular';

@Component({
  selector: 'app-tabs-disabled-tab-demo',
  imports: [AvTabsImports],
  template: `
<av-tabs class="w-full max-w-md" default-selected-key="active">
  <div av-tabs-list-container>
    <div av-tabs-list aria-label="Tabs with disabled">
      <span av-tabs-indicator></span>
      <button av-tabs-tab id="active">Active</button>
      <button av-tabs-tab id="disabled" disabled>Disabled</button>
      <button av-tabs-tab id="available">Available</button>
    </div>
  </div>
  <div class="pt-4" av-tabs-panel id="active">
    <p>This tab is active and can be selected.</p>
  </div>
  <div class="pt-4" av-tabs-panel id="disabled">
    <p>This content cannot be accessed.</p>
  </div>
  <div class="pt-4" av-tabs-panel id="available">
    <p>This tab is also available for selection.</p>
  </div>
</av-tabs>
`,
})
export class TabsDisabledTabDemo {}

With Separator

Add <span av-tabs-separator> inside each button[av-tabs-tab] (except the first) to display separator lines between tabs.

View your project overview and recent activity.

import { Component } from '@angular/core';
import { AvTabsImports } from '@avesra/angular';

@Component({
  selector: 'app-tabs-with-separator-demo',
  imports: [AvTabsImports],
  template: `
<av-tabs class="w-full max-w-md" default-selected-key="overview">
  <div av-tabs-list-container>
    <div av-tabs-list aria-label="Options">
      <span av-tabs-indicator></span>
      <button av-tabs-tab id="overview">Overview</button>
      <button av-tabs-tab id="analytics">
        <span av-tabs-separator></span>
        Analytics
      </button>
      <button av-tabs-tab id="reports">
        <span av-tabs-separator></span>
        Reports
      </button>
    </div>
  </div>
  <div class="pt-4" av-tabs-panel id="overview">
    <p>View your project overview and recent activity.</p>
  </div>
  <div class="pt-4" av-tabs-panel id="analytics">
    <p>Track your metrics and analyze performance data.</p>
  </div>
  <div class="pt-4" av-tabs-panel id="reports">
    <p>Generate and download detailed reports.</p>
  </div>
</av-tabs>
`,
})
export class TabsWithSeparatorDemo {}

Secondary Variant

View your project overview and recent activity.

import { Component } from '@angular/core';
import { AvTabsImports } from '@avesra/angular';

@Component({
  selector: 'app-tabs-secondary-demo',
  imports: [AvTabsImports],
  template: `
<av-tabs class="w-full max-w-md" variant="secondary" default-selected-key="overview">
  <div av-tabs-list-container>
    <div av-tabs-list aria-label="Options">
      <span av-tabs-indicator></span>
      <button av-tabs-tab id="overview">Overview</button>
      <button av-tabs-tab id="analytics">Analytics</button>
      <button av-tabs-tab id="reports">Reports</button>
    </div>
  </div>
  <div class="pt-4" av-tabs-panel id="overview">
    <p>View your project overview and recent activity.</p>
  </div>
  <div class="pt-4" av-tabs-panel id="analytics">
    <p>Track your metrics and analyze performance data.</p>
  </div>
  <div class="pt-4" av-tabs-panel id="reports">
    <p>Generate and download detailed reports.</p>
  </div>
</av-tabs>
`,
})
export class TabsSecondaryDemo {}

Secondary Variant Vertical

Account Settings

Manage your account information and preferences.

import { Component } from '@angular/core';
import { AvTabsImports } from '@avesra/angular';

@Component({
  selector: 'app-tabs-secondary-vertical-demo',
  imports: [AvTabsImports],
  template: `
<av-tabs class="w-full max-w-lg" variant="secondary" orientation="vertical" default-selected-key="account">
  <div av-tabs-list-container>
    <div av-tabs-list aria-label="Vertical tabs">
      <span av-tabs-indicator></span>
      <button av-tabs-tab id="account">Account</button>
      <button av-tabs-tab id="security">Security</button>
      <button av-tabs-tab id="notifications">Notifications</button>
      <button av-tabs-tab id="billing">Billing</button>
    </div>
  </div>
  <div class="px-4" av-tabs-panel id="account">
    <h3 class="mb-2 font-semibold">Account Settings</h3>
    <p class="text-sm text-muted">Manage your account information and preferences.</p>
  </div>
  <div class="px-4" av-tabs-panel id="security">
    <h3 class="mb-2 font-semibold">Security Settings</h3>
    <p class="text-sm text-muted">
      Configure two-factor authentication and password settings.
    </p>
  </div>
  <div class="px-4" av-tabs-panel id="notifications">
    <h3 class="mb-2 font-semibold">Notification Preferences</h3>
    <p class="text-sm text-muted">Choose how and when you want to receive notifications.</p>
  </div>
  <div class="px-4" av-tabs-panel id="billing">
    <h3 class="mb-2 font-semibold">Billing Information</h3>
    <p class="text-sm text-muted">View and manage your subscription and payment methods.</p>
  </div>
</av-tabs>
`,
})
export class TabsSecondaryVerticalDemo {}

Styling

Passing Tailwind CSS classes

<div class="w-full max-w-lg text-center">
  <av-tabs default-selected-key="daily">
    <div
      class="w-fit
        **:data-[slot=tabs-tab]:h-6
        **:data-[slot=tabs-tab]:w-fit
        **:data-[slot=tabs-tab]:px-3
        **:data-[slot=tabs-tab]:text-sm
        **:data-[slot=tabs-tab]:font-normal
        **:data-[slot=tabs-tab]:data-[selected=true]:text-accent-foreground
        **:data-[slot=tabs-indicator]:bg-accent
        **:data-[slot=tabs-indicator]:shadow-none"
      av-tabs-list-container
    >
      <div av-tabs-list aria-label="Options">
        <span av-tabs-indicator></span>
        <button av-tabs-tab id="daily">Daily</button>
        <button av-tabs-tab id="weekly">Weekly</button>
        <button av-tabs-tab id="bi-weekly">Bi-Weekly</button>
        <button av-tabs-tab id="monthly">Monthly</button>
      </div>
    </div>
    <div class="px-4" av-tabs-panel id="daily">
      <h3 class="mb-2 font-semibold">Daily</h3>
      <p class="text-sm text-muted">Manage your daily tasks and goals.</p>
    </div>
    <div class="px-4" av-tabs-panel id="weekly">
      <h3 class="mb-2 font-semibold">Weekly</h3>
      <p class="text-sm text-muted">Manage your weekly tasks and goals.</p>
    </div>
    <div class="px-4" av-tabs-panel id="bi-weekly">
      <h3 class="mb-2 font-semibold">Bi-Weekly</h3>
      <p class="text-sm text-muted">Manage your bi-weekly tasks and goals.</p>
    </div>
    <div class="px-4" av-tabs-panel id="monthly">
      <h3 class="mb-2 font-semibold">Monthly</h3>
      <p class="text-sm text-muted">Manage your monthly tasks and goals.</p>
    </div>
  </av-tabs>
</div>

CSS Classes

The Tabs component uses these CSS classes:

Base Classes

  • .av-tabs — Base tabs container
  • .av-tabs__list-container — Tab list container wrapper
  • .av-tabs__list-container__scroller — Scrollable wrapper around the tab list (handles overflow and fading edges)
  • .av-tabs__list-container__scroll-prev — Scroll chevron for previous (left / up)
  • .av-tabs__list-container__scroll-next — Scroll chevron for next (right / down)
  • .av-tabs__list — Tab list container
  • .av-tabs__tab — Individual tab button
  • .av-tabs__separator — Separator between tabs
  • .av-tabs__panel — Tab panel content
  • .av-tabs__indicator — Tab indicator

Orientation Attributes

  • .av-tabs[data-orientation="horizontal"] — Horizontal tab layout (default)
  • .av-tabs[data-orientation="vertical"] — Vertical tab layout

Variant Classes

  • .av-tabs--secondary — Secondary variant with underline indicator

Interactive States

The component supports both CSS pseudo-classes and data attributes:

  • Selected: [aria-selected="true"] or [data-selected="true"]
  • Hover: :hover or [data-hovered="true"]
  • Focus: :focus-visible or [data-focus-visible="true"]
  • Disabled: [aria-disabled="true"]

API Reference

PropTypeDefaultDescription
variant'default' | 'secondary''default'Visual style variant. Default uses a filled indicator; secondary uses an underline indicator (av-tabs).
orientation'horizontal' | 'vertical''horizontal'Tab layout orientation (av-tabs).
selectedKeystring | null—Controlled selected tab id. Supports two-way binding with [(selectedKey)] (av-tabs).
default-selected-keystring | nullnullDefault selected tab id for uncontrolled usage (av-tabs).
selectedKeyChangeEventEmitter<string | null>—Selection change handler (av-tabs).
disable-paginationbooleanfalseDisables overflow chevrons and scroll-shadow detection (div[av-tabs-list-container]).
aria-labelstring—Accessibility label for the tab list (div[av-tabs-list]).
idstring—Unique tab identifier matching the panel id (button[av-tabs-tab]).
disabledbooleanfalseWhether the tab is disabled. Skipped during keyboard navigation; uses aria-disabled (button[av-tabs-tab]).
idstring—Panel identifier matching the tab id (div[av-tabs-panel]).

Made with ❤ by SyntaxHertz. Open source and available on GitHub.