詳細ガイド
Angular Aria

タブ

概要

タブは、一度に1つのパネルのみが表示される階層化されたコンテンツセクションを表示します。ユーザーは、タブボタンをクリックするか、矢印キーを使用してタブリストをナビゲートすることで、パネルを切り替えます。

使い方

タブは、ユーザーが異なるビューやカテゴリーを切り替える際に、関連するコンテンツを個別のセクションに整理するのに適しています。

タブを使用する場合:

  • 関連するコンテンツを個別のセクションに整理する
  • 複数のカテゴリーを持つ設定パネルを作成する
  • 複数のトピックを持つドキュメントを構築する
  • 異なるビューを持つダッシュボードを実装する
  • ユーザーがコンテキストを切り替える必要があるコンテンツを表示する

タブを避ける場合:

  • シーケンシャルなフォームやウィザードを構築する(ステッパーパターンを使用)
  • ページ間をナビゲートする(ルーターナビゲーションを使用)
  • 単一のコンテンツセクションを表示する(タブは不要)
  • 7〜8個以上のタブがある(異なるレイアウトを検討)

機能

  • 選択モード - フォーカス時にタブを自動的にアクティブにするか、手動でのアクティベーションを要求します
  • キーボードナビゲーション - 矢印キー、Home、Endキーによる効率的なタブナビゲーション
  • 向き - 水平または垂直のタブリストレイアウト
  • 遅延コンテンツ - タブパネルは最初にアクティブになったときにのみレンダリングされます
  • 無効化されたタブ - フォーカス管理機能付きで個々のタブを無効化します
  • フォーカスモード - roving tabindexまたはactivedescendantによるフォーカス戦略
  • RTLサポート - 右から左へ記述する言語のナビゲーション

フォーカスに追従する選択

フォーカスに追従する選択では、矢印キーで移動するとタブがすぐにアクティブになります。これにより、即座にフィードバックが得られ、軽量なコンテンツに適しています。

この動作を有効にするには、タブリストに [selectionMode]="'follow'" を設定します。

手動でのアクティブ化

手動でのアクティブ化では、矢印キーは選択されたタブを変更せずにタブ間でフォーカスを移動します。ユーザーはSpaceキーまたはEnterキーを押して、フォーカスされたタブをアクティブにします。

重いコンテンツパネルで不要なレンダリングを避けるには、[selectionMode]="'explicit'" を使用します。

垂直タブ

設定パネルやナビゲーションサイドバーのようなインターフェースでは、タブを垂直に配置します。

タブリストに [orientation]="'vertical'" を設定します。ナビゲーションは上/下矢印キーに変わります。

コンテンツの遅延レンダリング

ng-templatengTabContent ディレクティブを使用すると、タブパネルが最初に表示されるまでレンダリングを遅延させることができます。

<div ngTabs>
  <ul ngTabList [(selectedTab)]="selectedTab">
    <li ngTab value="tab1">Tab 1</li>
    <li ngTab value="tab2">Tab 2</li>
  </ul>

  <div ngTabPanel value="tab1">
    <ng-template ngTabContent>
      <!-- このコンテンツは、タブ1が最初に表示されたときにのみレンダリングされます -->
      <app-heavy-component />
    </ng-template>
  </div>

  <div ngTabPanel value="tab2">
    <ng-template ngTabContent>
      <!-- このコンテンツは、タブ2が最初に表示されたときにのみレンダリングされます -->
      <app-another-component />
    </ng-template>
  </div>
</div>

デフォルトでは、パネルが非表示になった後もコンテンツはDOMに残ります。パネルが非アクティブ化されたときにコンテンツを削除するには、[preserveContent]="false" を設定します。

無効化されたタブ

特定のタブを無効にして、ユーザーの操作を防ぎます。無効化されたタブがキーボードフォーカスを受け取れるかどうかを制御します。

タブリストで [softDisabled]="true" の場合、無効化されたタブはフォーカスを受け取れますが、アクティブにはできません。[softDisabled]="false" の場合、無効化されたタブはキーボードナビゲーション中にスキップされます。

Testing

Angular Aria provides component harnesses for testing tabs components. Here is an example of how to use the harnesses in a component test:

import {ComponentFixture, TestBed} from '@angular/core/testing';
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
import {ComponentHarness, HarnessLoader} from '@angular/cdk/testing';
import {TabsHarness} from '@angular/aria/tabs/testing';
import {MyTabsComponent} from './my-tabs'; // Your component

// A simple harness to help query content inside the tab panel
class TestContentHarness extends ComponentHarness {
  static hostSelector = '.test-content';
  async getText(): Promise<string> {
    return (await this.host()).text();
  }
}

describe('MyTabsComponent', () => {
  let fixture: ComponentFixture<MyTabsComponent>;
  let loader: HarnessLoader;

  beforeEach(async () => {
    TestBed.configureTestingModule({
      imports: [MyTabsComponent],
    });

    fixture = TestBed.createComponent(MyTabsComponent);
    await fixture.whenStable();
    loader = TestbedHarnessEnvironment.loader(fixture);
  });

  it('should switch tabs and scope panel queries', async () => {
    const tabs = await loader.getHarness(TabsHarness);

    // Get all tabs
    const tabItems = await tabs.getTabs();
    expect(tabItems.length).toBe(3);

    // Verify initial selection
    expect(await tabItems[0].isSelected()).toBe(true);
    expect(await tabItems[1].isSelected()).toBe(false);

    // Query content inside the active tab panel
    // TabHarness automatically scopes queries to its associated panel
    const content = await tabItems[0].getHarness(TestContentHarness);
    expect(await content.getText()).toBe('Content 1');

    // Switch to the second tab
    await tabItems[1].select();

    // Verify selection updated
    expect(await tabItems[0].isSelected()).toBe(false);
    expect(await tabItems[1].isSelected()).toBe(true);
  });
});

APIリファレンス

詳細なAPIドキュメントについては、以下のAPIリファレンスを参照してください。