タブ
堅牢なフォーカス管理とキーボードナビゲーションサポートにより、アクセシビリティが高く、完全にカスタマイズ可能なタブインターフェースを簡単に作成できます。
インストール
開始するには、npm を介して Headless UI をインストールします。
npm install @headlessui/react
基本例
タブは、Tab.Group
、Tab.List
、Tab
、Tab.Panels
、およびTab.Panel
コンポーネントを使用して構築されています。デフォルトでは最初のタブが選択されており、任意のタブをクリックするか、キーボードで選択すると、対応するパネルがアクティブになります。
import { Tab } from '@headlessui/react' function MyTabs() { return ( <Tab.Group> <Tab.List> <Tab>Tab 1</Tab> <Tab>Tab 2</Tab> <Tab>Tab 3</Tab> </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel> <Tab.Panel>Content 2</Tab.Panel> <Tab.Panel>Content 3</Tab.Panel> </Tab.Panels> </Tab.Group> ) }
様々な状態のスタイル設定
Headless UI は、どのタブオプションが現在チェックされているか、ポップオーバーが開いているか閉じているか、メニューのどのアイテムが現在キーボードでアクティブになっているかなど、各コンポーネントに関する多くの状態を追跡します。
しかし、コンポーネントはヘッドレスであり、すぐに使える状態では完全にスタイルが設定されていないため、各状態に望ましいスタイルを自分で提供するまで、UIでこの情報を見ることはできません。
レンダープロップの使用
各コンポーネントは、レンダープロップを介して現在の状態に関する情報を公開しており、これを使用して条件付きで異なるスタイルを適用したり、異なるコンテンツをレンダリングしたりできます。
たとえば、Tab
コンポーネントはselected
状態を公開しており、タブが現在選択されているかどうかを示します。
import { Fragment } from 'react' import { Tab } from '@headlessui/react' function MyTabs() { return ( <Tab.Group> <Tab.List> <Tab as={Fragment}>
{({ selected }) => (/* Use the `selected` state to conditionally style the selected tab. */ <button className={selected ? 'bg-blue-500 text-white' : 'bg-white text-black'} > Tab 1 </button> )} </Tab> {/* ... */} </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel> {/* ... */} </Tab.Panels> </Tab.Group> ) }
各コンポーネントの完全なレンダープロップAPIについては、コンポーネントAPIドキュメントを参照してください。
データ属性の使用
各コンポーネントは、条件付きで異なるスタイルを適用するために使用できるdata-headlessui-state
属性を介して、現在の状態に関する情報を公開します。
レンダープロップAPIのいずれかの状態がtrue
の場合、それらはスペース区切りの文字列としてこの属性にリストされ、[attr~=value]
形式のCSS属性セレクターでターゲットにすることができます。
たとえば、2番目のタブがselected
の場合、いくつかの子Tab
コンポーネントを含むTab.Group
コンポーネントは次のようにレンダリングされます。
<!-- Rendered `Tab.Group` --> <div> <button data-headlessui-state="">Tab 1</button> <button data-headlessui-state="selected">Tab 2</button> <button data-headlessui-state="">Tab 3</button> </div> <div> <div data-headlessui-state="">Content 1</div> <div data-headlessui-state="selected">Content 2</div> <div data-headlessui-state="">Content 3</div> </div>
Tailwind CSSを使用している場合は、@headlessui/tailwindcssプラグインを使用して、ui-open:*
などの修飾子でこの属性をターゲットにすることができます。
import { Tab } from '@headlessui/react' function MyTabs() { return ( <Tab.Group> <Tab.List>
<Tab className="ui-selected:bg-blue-500 ui-selected:text-white ui-not-selected:bg-white ui-not-selected:text-black">Tab 1 </Tab> {/* ... */} </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel> {/* ... */} </Tab.Panels> </Tab.Group> ) }
タブの無効化
タブを無効にするには、Tab
コンポーネントでdisabled
プロップを使用します。無効なタブはマウスで選択できず、キーボードを使用してタブリストをナビゲーションする際にもスキップされます。
import { Tab } from '@headlessui/react' function MyTabs() { return ( <Tab.Group> <Tab.List> <Tab>Tab 1</Tab>
<Tab disabled>Tab 2</Tab><Tab>Tab 3</Tab> </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel> <Tab.Panel>Content 2</Tab.Panel> <Tab.Panel>Content 3</Tab.Panel> </Tab.Panels> </Tab.Group> ) }
タブの手動によるアクティブ化
デフォルトでは、ユーザーが矢印キーを使用してタブを移動すると、タブが自動的に選択されます。
ユーザーがEnter
キーまたはSpace
キーを押すまで現在のタブを変更しない場合は、Tab.Group
コンポーネントでmanual
プロップを使用します。これは、タブの選択がコストの高い操作を実行する場合に役立ち、不要に実行したくない場合に便利です。
import { Tab } from '@headlessui/react' function MyTabs() { return (
<Tab.Group manual><Tab.List> <Tab>Tab 1</Tab> <Tab>Tab 2</Tab> <Tab>Tab 3</Tab> </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel> <Tab.Panel>Content 2</Tab.Panel> <Tab.Panel>Content 3</Tab.Panel> </Tab.Panels> </Tab.Group> ) }
manual
プロップはマウス操作には影響しません。タブはクリックされるとすぐに選択されます。
垂直タブ
Tab.List
を垂直に表示するようにスタイル設定した場合は、vertical
プロップを使用して、左右の矢印キーではなく上下の矢印キーでナビゲーションできるようにし、支援技術用のaria-orientation
属性を更新します。
import { Tab } from '@headlessui/react' function MyTabs() { return (
<Tab.Group vertical><Tab.List> <Tab>Tab 1</Tab> <Tab>Tab 2</Tab> <Tab>Tab 3</Tab> </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel> <Tab.Panel>Content 2</Tab.Panel> <Tab.Panel>Content 3</Tab.Panel> </Tab.Panels> </Tab.Group> ) }
デフォルトタブの指定
デフォルトで選択されているタブを変更するには、Tab.Group
コンポーネントでdefaultIndex={number}
プロップを使用します。
import { Tab } from '@headlessui/react' function MyTabs() { return (
<Tab.Group defaultIndex={1}><Tab.List> <Tab>Tab 1</Tab>{/* Selects this tab by default */}<Tab>Tab 2</Tab><Tab>Tab 3</Tab> </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel>{/* Displays this panel by default */}<Tab.Panel>Content 2</Tab.Panel><Tab.Panel>Content 3</Tab.Panel> </Tab.Panels> </Tab.Group> ) }
範囲外のインデックスを指定した場合、最初のレンダリング時に最後の無効でないタブが選択されます。(たとえば、上記の例では、<Tab.Group defaultIndex={5}
は3番目のパネルを選択してレンダリングします。)
変更の監視
選択されたタブが変更されるたびに関数を実行するには、Tab.Group
コンポーネントでonChange
プロップを使用します。
import { Tab } from '@headlessui/react' function MyTabs() { return ( <Tab.Group
onChange={(index) => {console.log('Changed selected tab to:', index)}}> <Tab.List> <Tab>Tab 1</Tab> <Tab>Tab 2</Tab> <Tab>Tab 3</Tab> </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel> <Tab.Panel>Content 2</Tab.Panel> <Tab.Panel>Content 3</Tab.Panel> </Tab.Panels> </Tab.Group> ) }
アクティブなタブの制御
タブコンポーネントは、制御されたコンポーネントとしても使用できます。これを行うには、selectedIndex
を提供し、状態を自分で管理します。
import { useState } from 'react' import { Tab } from '@headlessui/react' function MyTabs() {
const [selectedIndex, setSelectedIndex] = useState(0)return (<Tab.Group selectedIndex={selectedIndex} onChange={setSelectedIndex}><Tab.List> <Tab>Tab 1</Tab> <Tab>Tab 2</Tab> <Tab>Tab 3</Tab> </Tab.List> <Tab.Panels> <Tab.Panel>Content 1</Tab.Panel> <Tab.Panel>Content 2</Tab.Panel> <Tab.Panel>Content 3</Tab.Panel> </Tab.Panels> </Tab.Group> ) }
アクセシビリティに関する注意
マウス操作
Tab
をクリックすると、そのタブが選択され、対応するTab.Panel
が表示されます。
キーボード操作
Tab
コンポーネントにフォーカスがある場合、すべての操作が適用されます。
コマンド | 説明 |
左矢印および右矢印 | 前後の無効でないタブを選択します。 |
上矢印および下矢印( | 前後の無効でないタブを選択します。 |
HomeまたはPageUp | 最初の無効でないタブを選択します。 |
EndまたはPageDown | 最後の無効でないタブを選択します。 |
EnterまたはSpace( | 選択されたタブをアクティブにします。 |
その他
関連するすべてのARIA属性は自動的に管理されます。
タブ
に実装されているすべてのアクセシビリティ機能の完全なリファレンスについては、タブに関するARIA仕様を参照してください。
コンポーネントAPI
Tab.Group
メインのTab.Groupコンポーネント。
プロップ | デフォルト | 説明 |
as | Fragment | 文字列 | コンポーネント
|
defaultIndex | 0 | 数値 デフォルトで選択されているインデックス |
selectedIndex | — | 数値 タブコンポーネントを制御されたコンポーネントとして使用する場合は、選択されたインデックス。 |
onChange | — | (index: number) => void アクティブなタブが変更されるたびに呼び出される関数。 |
vertical | false | ブール値 trueの場合、 |
manual | false | ブール値 trueの場合、ユーザーはキーボードを使用してパネルを表示するには、最初に矢印キーを使用してパネルに移動してから、 |
レンダープロップ | 説明 |
selectedIndex |
現在選択されているインデックス。 |
プロップ | デフォルト | 説明 |
as | div | 文字列 | コンポーネント
|
レンダープロップ | 説明 |
selectedIndex |
現在選択されているインデックス。 |
プロップ | デフォルト | 説明 |
as | button | 文字列 | コンポーネント
|
disabled | false | ブール値
|
レンダープロップ | 説明 |
selected |
|
プロップ | デフォルト | 説明 |
as | div | 文字列 | コンポーネント
|
レンダープロップ | 説明 |
selectedIndex |
現在選択されているインデックス。 |
プロップ | デフォルト | 説明 |
as | div | 文字列 | コンポーネント
|
静的 | false | ブール値 選択されたインデックスを無視するかどうか。 注: |
アンマウント | true | ブール値 選択されたインデックスに基づいて、要素をアンマウントするか非表示にするかどうか。 注: |
レンダープロップ | 説明 |
selected |
|