syncfusion-react-tabs について
Syncfusion React の Tab コンポーネントでタブ UI を構築するためのリファレンススキルです。初期設定、コンテンツ描画、アクセシビリティ、カスタマイズ、プログラム制御を扱います。
主な機能
- 01ヘッダー位置とオーバーフローの設定
- 02コンテンツ描画方式の選択
- 03ドラッグ&ドロップでのタブ並べ替え
- 04アクセシビリティとローカライズ対応
- 05コンポーネントメソッドによるタブ制御
活用シーン
- 01レスポンシブなタブ画面の構築
- 02タブ切り替え後の状態維持
- 03ユーザーによるタブの並べ替え
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ syncfusion/ react-ui-components-skills --skill syncfusion-react-tabsインストール後、Claude Code で/syncfusion-react-tabsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/accessibility-localization.mdcontent-rendering.mddrag-drop-reordering.mdgetting-started.mdheader-styling.mdorientation-overflow.md詳細
Syncfusion React でのタブの実装
Tab コンポーネントは、ヘッダー付きのタブセクションに関連するコンテンツを整理し、ユーザーがビューを切り替えられるようにします。この包括的なスキルでは、セットアップ、カスタマイズ、コンテンツのレンダリング方法、API メソッド、イベント、アクセシビリティ、アニメーション、状態の保持、ドラッグ&ドロップによる並べ替えなどの高度な機能について説明します。
目次
- このスキルを使うタイミング
- コンポーネントの概要
- ドキュメントとナビゲーションガイド
- クイックスタートの例
- 一般的なパターン
- 主なプロパティの概要
- メソッドと API リファレンス
- イベントとイベント引数
- アニメーションと詳細設定
- 関連スキル
このスキルを使うタイミング
- ヘッダーベースのナビゲーションを備えたタブ付きインターフェイスを作成する
- コンテンツを論理的なセクションやビューに整理する
- スクロール可能なオーバーフロー処理やポップアップによるオーバーフロー処理を備えたレスポンシブレイアウトを構築する
- ヘッダーのスタイルやアイコンの配置をカスタマイズする
- コンテンツのレンダリング性能(遅延読み込み、動的レンダリング、初期レンダリング)を管理する
- ユーザーがカスタマイズできるよう、ドラッグ&ドロップによるタブの並べ替えを実装する
- 国際的なアプリケーション向けにローカライズをサポートする
- アクセシビリティへの準拠(WCAG、ARIA、キーボードナビゲーション)を確保する
- カスタム CSS やテーマのカスタマイズでタブをスタイリングする
- タブをプログラムから管理する(追加、削除、選択、表示/非表示)
- タブ関連のイベント(選択、ドラッグ&ドロップ、追加、削除)を処理する
- 状態の保持によってユーザー設定を保持する
- スムーズなアニメーションとトランジションを実装する
コンポーネントの概要
Tab コンポーネントは、タブに整理されたコンテンツを表示するナビゲーションコントロールです。各タブにはヘッダーと関連するコンテンツがあります。タブでは、次の機能がサポートされています。
- 複数のヘッダー位置(上、下、左、右)
- オーバーフロー処理(スクロール可能なナビゲーションまたはポップアップモード)
- 柔軟なコンテンツレンダリング(必要時、動的、または初回読み込み時)
- 対話的なタブ管理のためのドラッグ&ドロップによる並べ替え
- ARIA 属性とキーボードナビゲーションによる完全なアクセシビリティ
- CSS とテーマオプションによる幅広いカスタマイズ
- ローカライズ API による国際化
- コンテンツ切り替え時のアニメーション効果
- ページ再読み込み後も状態を保持
- セキュリティのためのHTML サニタイズ
ドキュメントとナビゲーションガイド
はじめに
📄 参照: references/getting-started.md
- パッケージの依存関係とインストール
- Vite と Create React App のセットアップ
- CSS のインポートとテーマの設定
- JSON アイテムを使った基本的なタブの初期化
- 最小限の実行可能な例とアプリの実行
参照するタイミング: まずこちらを読み、React アプリケーションで基本的な Tab コンポーネントをセットアップしてください。
ヘッダーのスタイリングとカスタマイズ
📄 参照: references/header-styling.md
- 組み込みのヘッダースタイルクラス(e-fill、e-background、e-accent)
- アイコンの配置オプション(左、右、上、下)
- CSS クラスを使ったアイコンとヘッダーのカスタマイズ
- スタイル設定されたヘッダーのコード例
- コンテンツとホバー状態のスタイリング
参照するタイミング: タブヘッダーの外観をカスタマイズしたり、アイコンを追加したり、定義済みのスタイルを適用したりする場合に参照してください。
方向とオーバーフローモード
📄 参照: references/orientation-overflow.md
- ヘッダーの配置位置(上、下、左、右)
- ナビゲーション矢印を備えたスクロール可能モード
- ドロップダウン表示によるポップアップモード
- タッチとスワイプのサポート
- 幅の制約とレスポンシブな動作
参照するタイミング: ヘッダーの位置を制御したり、多数のタブによるオーバーフローを処理したり、レスポンシブレイアウトを構築したりする場合に参照してください。
コンテンツのレンダリング方法
📄 参照: references/content-rendering.md
- オンデマンドレンダリング(遅延読み込み、デフォルトモード)
- 状態を分離したタブの動的レンダリング
- 状態を保持する初期レンダリング
- パフォーマンスと状態に関する考慮事項
- 適切なレンダリングモードの選択
読むタイミング: タブコンテンツのパフォーマンスを最適化する場合や、タブ切り替え時にユーザーの操作を保持する場合に参照してください。
ドラッグ&ドロップによる並べ替え
📄 参照: references/drag-drop-reordering.md
- allowDragAndDrop によるドラッグ&ドロップの有効化
- ドラッグイベントの処理(onDragStart、dragging、dragged)
- 特定の項目でのドラッグ/ドロップの防止
- タブ間のドラッグ&ドロップ
- タブを外部のソース(TreeView)にドラッグ
- ドラッグ領域の制約
読むタイミング: ユーザーがタブを並べ替えられるようにする場合や、タブのドラッグを他のコンポーネントと連携させる場合に参照してください。
アクセシビリティとローカライズ
📄 参照: references/accessibility-localization.md
- WCAG 2.2 および Section 508 への準拠
- タブの ARIA 属性とロール
- キーボード操作(矢印、Home、End、Enter、Escape)
- スクリーンリーダーのサポート
- L10n クラスによるローカライズ
- 右から左に記述する言語(RTL)のサポート
読むタイミング: アクセシブルなアプリケーションを構築する場合や、複数の言語に対応する場合に参照してください。
クイックスタートの例
最小限の Tab コンポーネントの設定例を次に示します。
import React from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
import '@syncfusion/ej2-base/styles/tailwind3.css';
import '@syncfusion/ej2-buttons/styles/tailwind3.css';
import '@syncfusion/ej2-popups/styles/tailwind3.css';
import '@syncfusion/ej2-react-navigations/styles/tailwind3.css';
export default function TabExample() {
const tabItems = [
{
header: { text: 'Home' },
content: 'Welcome to the home tab'
},
{
header: { text: 'Profile' },
content: 'User profile information'
},
{
header: { text: 'Settings' },
content: 'Application settings'
}
];
return (
<TabComponent>
<TabItemsDirective>
{tabItems.map((item, index) => (
<TabItemDirective key={index} header={item.header} content={item.content} />
))}
</TabItemsDirective>
</TabComponent>
);
}
よくあるパターン
パターン 1:アイコン付きのスタイル設定済みタブ
<TabComponent className="e-fill">
<TabItemsDirective>
<TabItemDirective
header={{ text: 'Home', iconCss: 'e-icons e-home' }}
content="Home content"
/>
<TabItemDirective
header={{ text: 'Profile', iconCss: 'e-icons e-user' }}
content="Profile content"
/>
</TabItemsDirective>
</TabComponent>
パターン 2:左側に配置する縦向きのタブ
<TabComponent headerPlacement="Left">
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
</TabItemsDirective>
</TabComponent>
パターン 3:遅延読み込みコンテンツ(デフォルト)
<TabComponent>
<TabItemsDirective>
<TabItemDirective
header={{ text: 'Lazy Tab' }}
content={() => <ExpensiveComponent />}
/>
</TabItemsDirective>
</TabComponent>
パターン 4:ドラッグ可能なタブ
<TabComponent allowDragAndDrop={true}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
</TabItemsDirective>
</TabComponent>
主なプロパティの概要
| プロパティ | 型 | デフォルト | 用途 |
|---|---|---|---|
headerPlacement | String | 'Top' | タブヘッダーの位置:Top、Bottom、Left、Right |
overflowMode | String | 'Scrollable' | オーバーフローの処理方法:Scrollable または Popup |
loadOn | String | 'Demand' | コンテンツのレンダリング方法:Demand、Dynamic、Init |
allowDragAndDrop | Boolean | false | ドラッグ&ドロップによるタブの並べ替えを有効にします |
showCloseButton | Boolean | false | タブヘッダーに閉じるボタンを表示します |
locale | String | 'en-US' | ローカライズのカルチャコード(例:'fr-FR') |
width | String/Number | '100%' | タブコンテナーの幅 |
height | String/Number | 'auto' | タブコンテナーの高さ |
heightAdjustMode | String | 'Content' | 高さの調整モード:None、Auto、Content、Fill |
selectedItem | Number | 0 | アクティブなタブのインデックス |
enablePersistence | Boolean | false | 再読み込み後も選択したタブの状態を保持します |
enableHtmlSanitizer | Boolean | true | セキュリティのために HTML コンテンツをサニタイズします |
cssClass | String | '' | コンポーネントに適用するカスタム CSS クラス |
enableRtl | Boolean | false | 右から左へのレイアウトを有効にします |
scrollStep | Number | null | スクロール矢印を使用したときのスクロール距離 |
reorderActiveTab | Boolean | true | アクティブなタブがヘッダー領域に表示されるように並べ替えます |
clearTemplates | Boolean | true | 項目が動的に変更されたときにテンプレートをクリアします |
dragArea | String | null | タブの並べ替えができるドラッグ領域を制限します |
swipeMode | String | 'Both' | スワイプの検出方法:Both、Touch、Mouse、None |
animation | TabAnimationSettingsModel | Default | タブ切り替え時のアニメーション設定 |
メソッドと API リファレンス
addTab(items, index)
Tab コンポーネントに新しい項目を追加します。項目は指定したインデックスに挿入されます。
パラメーター:
items- 追加するTabItemModelオブジェクトの配列index(任意)- 項目を挿入する位置です。デフォルトは 0 です。
戻り値: void
例:
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function AddTabExample() {
const tabRef = useRef(null);
const handleAddTab = () => {
const newItems = [
{
header: { text: 'New Tab' },
content: 'This is dynamically added content'
}
];
// Add at the end (index 2 if there are 2 existing tabs)
tabRef.current.addTab(newItems, 2);
};
return (
<div>
<button onClick={handleAddTab}>Add Tab</button>
<TabComponent ref={tabRef}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
removeTab(index)
指定したインデックスのタブ項目を削除します。
パラメーター:
index- 削除するタブのインデックス
戻り値: void
例:
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function RemoveTabExample() {
const tabRef = useRef(null);
const handleRemoveTab = (tabIndex) => {
tabRef.current.removeTab(tabIndex);
};
return (
<div>
<button onClick={() => handleRemoveTab(1)}>Remove Tab 2</button>
<TabComponent ref={tabRef} showCloseButton={true}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
<TabItemDirective header={{ text: 'Tab 3' }} content="Content 3" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
select(args, event)
インデックスまたは DOM 要素でタブを選択します。プログラムから別のタブに切り替えます。
パラメーター:
args- 選択するタブのインデックス(数値)または HTMLElementevent(省略可能) - DOM イベントオブジェクト
戻り値: void
例:
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function SelectTabExample() {
const tabRef = useRef(null);
const handleSelectTab = (index) => {
tabRef.current.select(index);
};
return (
<div>
<div>
<button onClick={() => handleSelectTab(0)}>Select Tab 1</button>
<button onClick={() => handleSelectTab(1)}>Select Tab 2</button>
<button onClick={() => handleSelectTab(2)}>Select Tab 3</button>
</div>
<TabComponent ref={tabRef}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
<TabItemDirective header={{ text: 'Tab 3' }} content="Content 3" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
enableTab(index, value)
特定のタブ項目を有効または無効にします。無効にしたタブは選択できませんが、表示されたままになります。
パラメーター:
index- 有効/無効にするタブのインデックスvalue- ブール値。trueで有効、falseで無効
戻り値: void
例:
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function EnableTabExample() {
const tabRef = useRef(null);
const toggleTabEnabled = (index) => {
const isCurrentlyEnabled = !tabRef.current.items[index].isDisabled;
tabRef.current.enableTab(index, isCurrentlyEnabled);
};
return (
<div>
<button onClick={() => toggleTabEnabled(1)}>Toggle Tab 2 Enable</button>
<TabComponent ref={tabRef}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
<TabItemDirective header={{ text: 'Tab 3' }} content="Content 3" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
hideTab(index, value)
指定したインデックスのタブ項目を表示または非表示にします。非表示のタブは DOM から削除されます。
パラメーター:
index- 表示/非表示にするタブのインデックスvalue(省略可能) - ブール値。trueで非表示、falseで表示します。デフォルトはtrueです
戻り値: void
例:
import React, { useRef, useState } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function HideTabExample() {
const tabRef = useRef(null);
const [visibleTabs, setVisibleTabs] = useState([true, true, true]);
const toggleTabVisibility = (index) => {
const newVisibleTabs = [...visibleTabs];
newVisibleTabs[index] = !newVisibleTabs[index];
setVisibleTabs(newVisibleTabs);
tabRef.current.hideTab(index, !newVisibleTabs[index]);
};
return (
<div>
<div>
<button onClick={() => toggleTabVisibility(0)}>
Toggle Tab 1 Visibility
</button>
<button onClick={() => toggleTabVisibility(1)}>
Toggle Tab 2 Visibility
</button>
</div>
<TabComponent ref={tabRef}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
<TabItemDirective header={{ text: 'Tab 3' }} content="Content 3" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
getItemIndex(tabItemId)
ID を指定してタブ項目のインデックスを取得します。
パラメーター:
tabItemId- タブ項目の ID
戻り値: number - タブのインデックス。見つからない場合は -1
例:
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function GetItemIndexExample() {
const tabRef = useRef(null);
const findTabIndex = () => {
const itemId = 'tab_2';
const index = tabRef.current.getItemIndex(itemId);
console.log(`Tab with ID '${itemId}' is at index: ${index}`);
};
return (
<div>
<button onClick={findTabIndex}>Find Tab Index</button>
<TabComponent ref={tabRef}>
<TabItemsDirective>
<TabItemDirective id="tab_1" header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective id="tab_2" header={{ text: 'Tab 2' }} content="Content 2" />
<TabItemDirective id="tab_3" header={{ text: 'Tab 3' }} content="Content 3" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
refresh()
Tab コンポーネント全体を更新します。項目やプロパティを動的に変更した後に便利です。
パラメーター: なし
戻り値: void
例:
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function RefreshTabExample() {
const tabRef = useRef(null);
const handleRefresh = () => {
tabRef.current.refresh();
console.log('Tab component refreshed');
};
return (
<div>
<button onClick={handleRefresh}>Refresh Tab</button>
<TabComponent ref={tabRef}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
refreshActiveTab()
現在アクティブなタブのコンテンツのみを更新します。他のタブは再読み込みしません。
パラメーター: なし
戻り値: void
例:
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function RefreshActiveTabExample() {
const tabRef = useRef(null);
const handleRefreshActive = () => {
tabRef.current.refreshActiveTab();
console.log('Active tab content refreshed');
};
return (
<div>
<button onClick={handleRefreshActive}>Refresh Active Tab</button>
<TabComponent ref={tabRef}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Dynamically updated content" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
refreshActiveTabBorder()
アクティブなタブの視覚的なインジケーター(下線/境界線)を更新します。スタイル変更後に便利です。
パラメーター: なし
戻り値: void
例:
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function RefreshBorderExample() {
const tabRef = useRef(null);
const handleRefreshBorder = () => {
tabRef.current.refreshActiveTabBorder();
};
return (
<div>
<button onClick={handleRefreshBorder}>Refresh Border</button>
<TabComponent ref={tabRef}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
refreshOverflow()
コンポーネント全体を再描画せずに、利用可能な幅に収まるよう Tab のヘッダーを再配置して調整します。レスポンシブレイアウトに便利です。
パラメーター: なし
戻り値: void
例:
import React, { useRef, useState } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function RefreshOverflowExample() {
const tabRef = useRef(null);
const [tabCount, setTabCount] = useState(3);
const handleWindowResize = () => {
if (tabRef.current) {
tabRef.current.refreshOverflow();
}
};
React.useEffect(() => {
window.addEventListener('resize', handleWindowResize);
return () => window.removeEventListener('resize', handleWindowResize);
}, []);
const addMoreTabs = () => {
const newTab = {
header: { text: `Tab ${tabCount + 1}` },
content: `Content ${tabCount + 1}`
};
tabRef.current.addTab([newTab]);
setTabCount(tabCount + 1);
tabRef.current.refreshOverflow();
};
return (
<div>
<button onClick={addMoreTabs}>Add Tab & Refresh Overflow</button>
<TabComponent ref={tabRef} width="100%">
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
<TabItemDirective header={{ text: 'Tab 3' }} content="Content 3" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
disable(value)
Tab コンポーネント全体を無効または有効にします。
パラメーター:
value- ブール値。trueで無効、falseで有効
戻り値: void
例:
import React, { useRef, useState } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function DisableTabExample() {
const tabRef = useRef(null);
const [isDisabled, setIsDisabled] = useState(false);
const toggleDisable = () => {
tabRef.current.disable(!isDisabled);
setIsDisabled(!isDisabled);
};
return (
<div>
<button onClick={toggleDisable}>
{isDisabled ? 'Enable' : 'Disable'} Tab Component
</button>
<TabComponent ref={tabRef}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
destroy()
コンポーネントを DOM から削除し、すべてのイベントハンドラー、属性、クラスを切り離します。
パラメーター: なし
戻り値: void
例:
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function DestroyTabExample() {
const tabRef = useRef(null);
const handleDestroy = () => {
tabRef.current.destroy();
console.log('Tab component destroyed');
};
return (
<div>
<button onClick={handleDestroy}>Destroy Tab</button>
<TabComponent ref={tabRef}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
イベントとイベント引数
Tab コンポーネントは、ユーザー操作やコンポーネントの状態変化を処理するための包括的なイベントサポートを提供します。
selected
タブ項目が選択された後に発生します。ユーザーが別のタブに切り替えたときにアクションを実行するために使用します。
イベント引数: SelectEventArgs
SelectEventArgs のプロパティ:
selectedIndex(number) - 新しく選択されたタブのインデックスselectedItem(HTMLElement) - 選択されたタブの DOM 要素selectedContent(HTMLElement) - 選択されたタブのコンテンツ領域previousIndex(number) - 以前に選択されていたタブのインデックスpreviousItem(HTMLElement) - 以前のタブの DOM 要素isInteracted(boolean) - 選択がユーザー操作(true)によるものか、プログラムからの操作(false)によるものかisSwiped(boolean) - 選択がスワイプ操作によるものかpreventFocus(boolean) - 選択されたタブにフォーカスが移るのを防ぐには true に設定しますcancel(boolean) - 選択を防ぐには true に設定します
例:
import React, { useRef, useState } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function SelectedEventExample() {
const tabRef = useRef(null);
const [selectedIndex, setSelectedIndex] = useState(0);
const handleTabSelected = (args) => {
console.log('Tab selected:', {
selectedIndex: args.selectedIndex,
previousIndex: args.previousIndex,
isInteracted: args.isInteracted,
isSwiped: args.isSwiped
});
setSelectedIndex(args.selectedIndex);
};
return (
<div>
<p>Currently selected tab index: {selectedIndex}</p>
<TabComponent ref={tabRef} selected={handleTabSelected}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
<TabItemDirective header={{ text: 'Tab 3' }} content="Content 3" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
selecting
タブ項目が選択される前に発生します。特定の条件下で選択を防ぐために使用します。
イベント引数: SelectingEventArgs(SelectEventArgs と同じプロパティ)
例:
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function SelectingEventExample() {
const handleTabSelecting = (args) => {
// Prevent selection of tab at index 1
if (args.selectedIndex === 1) {
console.log('Tab 2 selection prevented');
args.cancel = true;
}
};
return (
<TabComponent selecting={handleTabSelecting}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2 (Locked)' }} content="Content 2" />
<TabItemDirective header={{ text: 'Tab 3' }} content="Content 3" />
</TabItemsDirective>
</TabComponent>
);
}
added
新しいタブ項目がコンポーネントに追加された後に発生します。
イベント引数: AddEventArgs
AddEventArgs のプロパティ:
addedItems(TabItemModel[]) - 追加されたタブ項目の配列name(string) - イベントの名前cancel(boolean) - アクションを防ぐには true に設定します
例:
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function AddedEventExample() {
const tabRef = useRef(null);
const handleTabAdded = (args) => {
console.log('Tabs added:', args.addedItems.length);
console.log('First added item header:', args.addedItems[0].header.text);
};
const handleAddTab = () => {
const newItems = [
{
header: { text: 'Newly Added Tab' },
content: 'This tab was added dynamically'
}
];
tabRef.current.addTab(newItems);
};
return (
<div>
<button onClick={handleAddTab}>Add Tab</button>
<TabComponent ref={tabRef} added={handleTabAdded}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
adding
新しいタブ項目が追加される前に発生します。追加前に項目を検証または変更するために使用します。
イベント引数: AddEventArgs
例:
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function AddingEventExample() {
const tabRef = useRef(null);
const maxTabs = 5;
const handleTabAdding = (args) => {
const totalTabs = tabRef.current.items.length + args.addedItems.length;
if (totalTabs > maxTabs) {
console.log(`Cannot exceed ${maxTabs} tabs`);
args.cancel = true;
}
};
const handleAddTab = () => {
const newItems = [
{
header: { text: `Tab ${tabRef.current.items.length + 1}` },
content: 'New content'
}
];
tabRef.current.addTab(newItems);
};
return (
<div>
<button onClick={handleAddTab}>Add Tab (Max 5)</button>
<TabComponent ref={tabRef} adding={handleTabAdding}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
removed
コンポーネントからタブ項目が削除された後に発火します。
イベント引数: RemoveEventArgs
RemoveEventArgs のプロパティ:
removedItem(HTMLElement) - 削除されたタブの DOM 要素index(number) - 削除されたタブのインデックスname(string) - イベント名
例:
import React, { useRef, useState } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function RemovedEventExample() {
const tabRef = useRef(null);
const [removedCount, setRemovedCount] = useState(0);
const handleTabRemoved = (args) => {
console.log(`Tab at index ${args.index} was removed`);
setRemovedCount(removedCount + 1);
};
const handleRemoveTab = (index) => {
tabRef.current.removeTab(index);
};
return (
<div>
<p>Tabs removed: {removedCount}</p>
<button onClick={() => handleRemoveTab(0)}>Remove First Tab</button>
<TabComponent ref={tabRef} removed={handleTabRemoved}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
<TabItemDirective header={{ text: 'Tab 3' }} content="Content 3" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
removing
タブ項目が削除される前に発火します。特定の条件下で削除を防ぐために使用します。
イベント引数: RemoveEventArgs
例:
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function RemovingEventExample() {
const handleTabRemoving = (args) => {
const confirmed = window.confirm('Are you sure you want to remove this tab?');
if (!confirmed) {
args.cancel = true;
}
};
return (
<TabComponent removing={handleTabRemoving} showCloseButton={true}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
<TabItemDirective header={{ text: 'Tab 3' }} content="Content 3" />
</TabItemsDirective>
</TabComponent>
);
}
onDragStart
タブ項目のドラッグが開始される前に発火します。特定のタブのドラッグを防いだり、ドラッグの動作をカスタマイズしたりできます。
イベント引数: DragEventArgs
DragEventArgs のプロパティ:
draggedItem(HTMLElement) - ドラッグ中のタブclonedElement(HTMLElement) - ドラッグ中の要素のクローンevent(MouseEvent) - ドラッグイベントindex(number) - ドラッグ中のタブのインデックスcancel(boolean) -trueに設定するとドラッグを防止しますname(string) - イベント名target(HTMLElement) - 対象要素droppedItem(HTMLElement) - ドロップ先の項目
例:
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function OnDragStartExample() {
const handleDragStart = (args) => {
// Prevent dragging the first tab (index 0)
if (args.index === 0) {
args.cancel = true;
console.log('First tab cannot be dragged');
}
};
return (
<TabComponent allowDragAndDrop={true} onDragStart={handleDragStart}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1 (Locked)' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
<TabItemDirective header={{ text: 'Tab 3' }} content="Content 3" />
</TabItemsDirective>
</TabComponent>
);
}
dragging
タブのドラッグ中に発火します。
イベント引数: DragEventArgs
例:
import React, { useRef, useState } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function DraggingEventExample() {
const [dragStatus, setDragStatus] = useState('');
const handleDragging = (args) => {
setDragStatus(`Dragging tab at index ${args.index}`);
};
return (
<div>
<p>Drag status: {dragStatus}</p>
<TabComponent allowDragAndDrop={true} dragging={handleDragging}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
<TabItemDirective header={{ text: 'Tab 3' }} content="Content 3" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
dragged
タブが新しい位置に正常にドロップされた後に発火します。
イベント引数: DragEventArgs
例:
import React, { useRef, useState } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function DraggedEventExample() {
const [dropMessage, setDropMessage] = useState('');
const handleDragged = (args) => {
setDropMessage(`Tab dropped at new position. Index: ${args.index}`);
console.log('Tab reordered successfully');
};
return (
<div>
<p>{dropMessage}</p>
<TabComponent allowDragAndDrop={true} dragged={handleDragged}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
<TabItemDirective header={{ text: 'Tab 3' }} content="Content 3" />
</TabItemsDirective>
</TabComponent>
</div>
);
}
created
Tab コンポーネントのレンダリングと初期化が完全に完了した後に発火します。
イベント引数: Event
例:
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function CreatedEventExample() {
const tabRef = useRef(null);
const handleCreated = () => {
console.log('Tab component created and initialized');
console.log('Total tabs:', tabRef.current.items.length);
};
return (
<TabComponent ref={tabRef} created={handleCreated}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
</TabItemsDirective>
</TabComponent>
);
}
destroyed
Tab コンポーネントが破棄され、DOM から削除されたときに発火します。
イベント引数: Event
例:
import React, { useRef, useState } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function DestroyedEventExample() {
const [showTab, setShowTab] = useState(true);
const handleDestroyed = () => {
console.log('Tab component destroyed');
alert('Tab component has been removed from DOM');
};
return (
<div>
<button onClick={() => setShowTab(!showTab)}>
{showTab ? 'Destroy' : 'Create'} Tab
</button>
{showTab && (
<TabComponent destroyed={handleDestroyed}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
</TabItemsDirective>
</TabComponent>
)}
</div>
);
}
アニメーションと詳細設定
Tab コンポーネントは、アニメーション、HTML のサニタイズ、状態の永続化などの高度な機能に対応しています。
アニメーションの設定
animation プロパティを使用して、選択時にタブのコンテンツが切り替わる際のトランジションを制御します。
アニメーションの設定項目:
previous- 前のタブに移動するときのアニメーション効果next- 次のタブに移動するときのアニメーション効果- 各アニメーションには、
effect、duration(ms)、easingがあります
使用可能なアニメーション効果:
SlideLeftIn- 右から左へのスライドSlideRightIn- 左から右へのスライドSlideUpIn- 下から上へのスライドSlideDownIn- 上から下へのスライドFadeIn- フェードイン効果FadeOut- フェードアウト効果FadeZoomIn- ズームインを伴うフェードFadeZoomOut- ズームアウトを伴うフェードZoomIn- ズームイン効果ZoomOut- ズームアウト効果None- アニメーションなし
例:カスタムアニメーション
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function AnimationExample() {
const tabRef = useRef(null);
const animationSettings = {
previous: { effect: 'SlideLeftIn', duration: 600, easing: 'ease' },
next: { effect: 'SlideRightIn', duration: 600, easing: 'ease' }
};
return (
<TabComponent ref={tabRef} animation={animationSettings}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Twitter' }} content="Twitter is an online social networking service..." />
<TabItemDirective header={{ text: 'Facebook' }} content="Facebook is an online social networking service..." />
<TabItemDirective header={{ text: 'WhatsApp' }} content="WhatsApp Messenger is a proprietary cross-platform instant messaging client..." />
</TabItemsDirective>
</TabComponent>
);
}
例:アニメーションを無効にする
import React from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function NoAnimationExample() {
const animationSettings = {
previous: { effect: 'None' },
next: { effect: 'None' }
};
return (
<TabComponent animation={animationSettings}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
</TabItemsDirective>
</TabComponent>
);
}
HTML のサニタイズ
HTML のサニタイズを有効にして、XSS 攻撃を防ぎます。enableHtmlSanitizer プロパティで、信頼できない HTML をサニタイズするかどうかを制御します。
例:HTML のサニタイズ
import React from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function HtmlSanitizationExample() {
return (
<div>
{/* Sanitization enabled (default) - malicious scripts are removed */}
<h2>With Sanitization (Safe)</h2>
<TabComponent enableHtmlSanitizer={true}>
<TabItemsDirective>
<TabItemDirective
header={{ text: 'Safe Content' }}
content="<b>Bold text</b> - This is safe HTML"
/>
<TabItemDirective
header={{ text: 'Dangerous Script' }}
content="<img src=x onerror='alert(\"XSS\")' /> - Script will be removed"
/>
</TabItemsDirective>
</TabComponent>
{/* Sanitization disabled - use only with trusted content */}
<h2>Without Sanitization (Use with Caution)</h2>
<TabComponent enableHtmlSanitizer={false}>
<TabItemsDirective>
<TabItemDirective
header={{ text: 'Trusted Content Only' }}
content="<b>Only use when content is from trusted sources</b>"
/>
</TabItemsDirective>
</TabComponent>
</div>
);
}
状態の永続化
enablePersistence プロパティを使用すると、Tab コンポーネントで選択中のタブをページの再読み込み後も保持できます。
例:状態の永続化
import React from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function PersistenceExample() {
return (
<div>
<p>
Select a different tab and refresh the page.
The previously selected tab will be restored.
</p>
<TabComponent enablePersistence={true} selectedItem={0}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'Twitter' }} content="Twitter is an online social networking service that enables users to send and read short 140-character messages..." />
<TabItemDirective header={{ text: 'Facebook' }} content="Facebook is an online social networking service headquartered in Menlo Park, California..." />
<TabItemDirective header={{ text: 'WhatsApp' }} content="WhatsApp Messenger is a proprietary cross-platform instant messaging client for smartphones..." />
</TabItemsDirective>
</TabComponent>
</div>
);
}
永続化される状態:
selectedItem- 現在アクティブなタブのインデックス
状態の保存と復元には、ブラウザーのローカルストレージを使用します。
スワイプナビゲーション
swipeMode プロパティを使用すると、スワイプ操作によるタブの移動を有効または無効にできます。モバイルデバイスやタッチインターフェイスで特に便利ですが、誤操作によるスワイプを防ぐようにカスタマイズできます。
SwipeMode のオプション:
Both(デフォルト)- タッチとマウスの両方でのスワイプを許可しますTouch- タッチ操作のみでのスワイプを許可しますMouse- マウス操作のみでのスワイプを許可しますNone- スワイプナビゲーションを完全に無効にします
例:誤操作によるタブの切り替えを防ぐためにスワイプを無効にする
import React from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function SwipeModeExample() {
return (
<div>
<h3>Form Tab - Swipe Disabled to Prevent Data Loss</h3>
<TabComponent heightAdjustMode='Auto' swipeMode='None'>
<TabItemsDirective>
<TabItemDirective
header={{ text: 'Personal Info' }}
content="Fill out your personal information without accidental swipes"
/>
<TabItemDirective
header={{ text: 'Address' }}
content="Enter your address details"
/>
<TabItemDirective
header={{ text: 'Confirmation' }}
content="Review and confirm your information"
/>
</TabItemsDirective>
</TabComponent>
<h3>Mobile Navigation - Touch Swipe Only</h3>
<TabComponent swipeMode='Touch'>
<TabItemsDirective>
<TabItemDirective
header={{ text: 'Twitter' }}
content="Twitter content - Swipe on mobile only"
/>
<TabItemDirective
header={{ text: 'Facebook' }}
content="Facebook content - Swipe on mobile only"
/>
<TabItemDirective
header={{ text: 'WhatsApp' }}
content="WhatsApp content - Swipe on mobile only"
/>
</TabItemsDirective>
</TabComponent>
</div>
);
}
例:マウスでのスワイプを無効にし、タッチでのスワイプを許可する
import React from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function TouchSwipeExample() {
return (
<TabComponent swipeMode='Touch'>
<TabItemsDirective>
<TabItemDirective
header={{ text: 'Dashboard' }}
content="Dashboard content - Swipe available on touch devices"
/>
<TabItemDirective
header={{ text: 'Analytics' }}
content="Analytics content"
/>
</TabItemsDirective>
</TabComponent>
);
}
タブのスクロール幅のカスタマイズ
scrollStep プロパティは、左右のナビゲーション矢印をクリックしたときにタブヘッダーがスクロールする距離(ピクセル単位)を制御します。タブが表示領域を超える場合に、スクロール動作を細かく調整するのに便利です。
例:スクロール幅のカスタマイズ
import React from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function ScrollStepExample() {
const htmlContent = () => {
return <div>
HyperText Markup Language, commonly referred to as HTML, is the standard markup language used to create web pages.
</div>;
};
const csharpContent = () => {
return <div>
C# is intended to be a simple, modern, general-purpose, object-oriented programming language.
</div>;
};
const javaContent = () => {
return <div>
Java is a set of computer software and specifications developed by Sun Microsystems.
</div>;
};
const vbNetContent = () => {
return <div>
The command-line compiler, VBC.EXE, is installed as part of the freeware .NET Framework SDK.
</div>;
};
const xamarinContent = () => {
return <div>
Xamarin is a software company created in May 2011 by the engineers that created Mono.
</div>;
};
const aspNetcontent = () => {
return <div>
ASP.NET is an open-source server-side web application framework designed for web development.
</div>;
};
const mvcContent = () => {
return <div>
The ASP.NET MVC is a web application framework developed by Microsoft.
</div>;
};
const jsContent = () => {
return <div>
JavaScript (JS) is an interpreted computer programming language.
</div>;
};
return (
<div>
<h3>Tab Scroll Step: 50px per click</h3>
<p>Click the left/right navigation arrows - tabs scroll 50 pixels at a time</p>
<TabComponent height="250px" scrollStep={50}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'HTML' }} content={htmlContent} />
<TabItemDirective header={{ text: 'C#' }} content={csharpContent} />
<TabItemDirective header={{ text: 'Java' }} content={javaContent} />
<TabItemDirective header={{ text: 'VB.Net' }} content={vbNetContent} />
<TabItemDirective header={{ text: 'Xamarin' }} content={xamarinContent} />
<TabItemDirective header={{ text: 'ASP.NET' }} content={aspNetcontent} />
<TabItemDirective header={{ text: 'ASP.NET MVC' }} content={mvcContent} />
<TabItemDirective header={{ text: 'JavaScript' }} content={jsContent} />
</TabItemsDirective>
</TabComponent>
<h3>Tab Scroll Step: 100px per click (Faster)</h3>
<p>Larger scroll step for quicker tab navigation</p>
<TabComponent height="250px" scrollStep={100}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'HTML' }} content={htmlContent} />
<TabItemDirective header={{ text: 'C#' }} content={csharpContent} />
<TabItemDirective header={{ text: 'Java' }} content={javaContent} />
<TabItemDirective header={{ text: 'VB.Net' }} content={vbNetContent} />
<TabItemDirective header={{ text: 'Xamarin' }} content={xamarinContent} />
<TabItemDirective header={{ text: 'ASP.NET' }} content={aspNetcontent} />
<TabItemDirective header={{ text: 'ASP.NET MVC' }} content={mvcContent} />
<TabItemDirective header={{ text: 'JavaScript' }} content={jsContent} />
</TabItemsDirective>
</TabComponent>
</div>
);
}
高度な設定:CSS クラスと RTL
CSS クラスのカスタマイズ
cssClass プロパティを使用して、カスタムスタイルを適用します。
import React from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
import './CustomTab.css';
export default function CustomCssExample() {
return (
<TabComponent cssClass="custom-tab-theme">
<TabItemsDirective>
<TabItemDirective header={{ text: 'Tab 1' }} content="Content 1" />
<TabItemDirective header={{ text: 'Tab 2' }} content="Content 2" />
</TabItemsDirective>
</TabComponent>
);
}
RTL(右から左)サポート
アラビア語、ヘブライ語などの RTL 言語向けに RTL レイアウトを有効にします。
import React from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function RTLExample() {
return (
<TabComponent enableRtl={true}>
<TabItemsDirective>
<TabItemDirective header={{ text: 'ملخص' }} content="محتوى في اللغة العربية" />
<TabItemDirective header={{ text: 'تفاصيل' }} content="المزيد من المحتوى" />
<TabItemDirective header={{ text: 'الإعدادات' }} content="إعدادات التطبيق" />
</TabItemsDirective>
</TabComponent>
);
}
高度な設定の組み合わせ例
import React, { useRef } from 'react';
import { TabComponent, TabItemsDirective, TabItemDirective } from '@syncfusion/ej2-react-navigations';
export default function AdvancedSettingsExample() {
const tabRef = useRef(null);
const handleTabSelecting = (args) => {
console.log(`Switching from tab ${args.previousIndex} to tab ${args.selectedIndex}`);
};
const animationSettings = {
previous: { effect: 'SlideLeftIn', duration: 500, easing: 'ease-out' },
next: { effect: 'SlideRightIn', duration: 500, easing: 'ease-out' }
};
return (
<TabComponent
ref={tabRef}
headerPlacement="Top"
overflowMode="Scrollable"
enablePersistence={true}
enableHtmlSanitizer={true}
enableRtl={false}
cssClass="advanced-tab-demo"
animation={animationSettings}
heightAdjustMode="Auto"
selecting={handleTabSelecting}
>
<TabItemsDirective>
<TabItemDirective
header={{ text: 'Overview', iconCss: 'e-icons e-home' }}
content="Welcome to the overview tab"
/>
<TabItemDirective
header={{ text: 'Profile', iconCss: 'e-icons e-user' }}
content="User profile information"
/>
<TabItemDirective
header={{ text: 'Settings', iconCss: 'e-icons e-settings' }}
content="Application settings"
/>
</TabItemsDirective>
</TabComponent>
);
}
関連するスキル
- アコーディオンの実装 - 折りたたみ可能なコンテンツ向けの類似したナビゲーションコンポーネント
- サイドバーの実装 - 補完的なナビゲーションパターン
- パンくずリストの実装 - タブと併用するナビゲーションコンテキスト