タブ
hc-tabs は、同じクラス名と見た目のもとに 2 つのマークアップ
パターンを提供します:
| パターン | 使いどころ | マークアップ | JS 必要? |
|---|---|---|---|
| アプリ状態 | 単一ページが URL を変えずにパネルを切り替える。 | <div role="tablist"> + <button role="tab"> + <div role="tabpanel"> | はい — installTabs() がロービングタブインデックス、矢印キー、パネル切り替えを配線。 |
| URL ルーティング | 各タブが独自の URL またはクエリパラメータ。 | <nav> + aria-current="page" つきの <a href> | いいえ — ブラウザネイティブのリンクセマンティクスがキーボードとフォーカスをすでに処理。 |
アプリ状態パターンは WAI-ARIA APG のタブパターンに 従い、デフォルトで手動アクティベーションを使います — パネルが htmx で遅延読み込みされるとき、矢印キーのたびにリクエストが飛ばない ようにするためです。
別名: タブ切り替え、タブバー。
アプリ状態タブ
Section titled “アプリ状態タブ”General account settings.
Billing details.
Team members.
<div class="hc-tabs"> <div class="hc-tabs__list" role="tablist" aria-label="Account"> <button type="button" class="hc-tabs__tab" role="tab" id="tab-general" aria-controls="panel-general" aria-selected="true" tabindex="0">General</button> <button type="button" class="hc-tabs__tab" role="tab" id="tab-billing" aria-controls="panel-billing" aria-selected="false" tabindex="-1">Billing</button> <button type="button" class="hc-tabs__tab" role="tab" id="tab-team" aria-controls="panel-team" aria-selected="false" tabindex="-1">Team</button> </div>
<div class="hc-tabs__panel" role="tabpanel" id="panel-general" aria-labelledby="tab-general" tabindex="0"> General settings panel. </div> <div class="hc-tabs__panel" role="tabpanel" id="panel-billing" aria-labelledby="tab-billing" tabindex="0" hidden="until-found"> Billing details panel. </div> <div class="hc-tabs__panel" role="tabpanel" id="panel-team" aria-labelledby="tab-team" tabindex="0" hidden="until-found"> Team members panel. </div></div>import { installTabs } from '@hypermedia-components/core';installTabs();installTabs() は冪等で、アンインストーラを返します。ゼロ設定の
@hypermedia-components/core/behaviors エントリが自動インストールし、
htmx でスワップされた内容も自動で拾います。
パネルがアクティブになると、ビヘイビアはそのパネル上でバブリングする
hc:tabactivated イベントを発行します(detail ペイロードは
ありません — イベントターゲット自体がパネルです)。タブ切り替えへの
反応に使えます。例えばパネル内容の遅延読み込みなど
(htmx での利用を参照)。
アクティベーションモード
Section titled “アクティベーションモード”デフォルトでビヘイビアは手動アクティベーションを使います —
矢印キーはフォーカスを動かし、ユーザーは Enter または Space で
確定します。パネルが遅延読み込みされる(htmx、
IntersectionObserver)場合、フォーカスだけではリクエストが発火しない
これが正しいデフォルトです。
タブがフォーカスを受けた瞬間にパネルをアクティブにするには、
data-activation="automatic" でオプトインします:
<div class="hc-tabs" data-activation="automatic">…</div><div class="hc-tabs" data-variant="pill">…</div>data-variant | スタイル |
|---|---|
default | アクティブタブに下線のインジケーター。 |
pill | アクティブタブに塗りつぶし背景。リストはベースラインを落とします。 |
data-size は sm、md(デフォルト)、lg を受け付けます。
デフォルトサイズは data-density にも従うため、密なレイアウトは
タブごとの作業なしで縮みます。
<div class="hc-tabs" data-size="sm">…</div>オーバーフロー(スクロール可能)
Section titled “オーバーフロー(スクロール可能)”デフォルトでは、タブリストは余地がなくなると 2 行目へ折り返し
ます。代わりに横スクロール可能な 1 行に保つには
data-overflow="scroll" を足します:
<div class="hc-tabs" data-overflow="scroll"> <div class="hc-tabs__list" role="tablist" aria-label="Sections"> <button type="button" class="hc-tabs__tab" role="tab" …>Overview</button> <!-- …many tabs… --> </div> <!-- panels --></div>残りは installTabs() がやります:
- その方向にまだスクロールできるときだけ現れる端のスクロール ボタン(マウス向けの操作部)を注入します。タブ順の外にあります — キーボードユーザーは矢印キーに頼り、それがすでにスクロールします。
- アクティブなタブとフォーカス中のタブは見える位置に保たれます: 矢印キーのナビゲーション、アクティベーション、初期選択タブのいずれも 見える行の中へスクロールします。
- タッチ / トラックパッドのスクロールはネイティブに動きます。 スクロールバーは隠れます。
- 方向対応です — RTL ではボタンが反対の端へ移り、シェブロンが ミラーされます。
スクロールボタンは装飾(aria-hidden)なので、アクセシブルなタブ
パターンへの純粋な追加です。
ルートに data-orientation="vertical" を足すと、タブリストがパネルの
横に列として立ちます。installTabs() はこれを tablist の
aria-orientation="vertical" に反映し、矢印キーの軸が切り替わり
ます: ↑ / ↓ がタブ間を移動し
(← / → の代わり)、Home /
End とアクティベーションは変わりません。アクティブ
インジケーターは下線から inline-start のバーに移ります(論理なので
RTL で反転します)。
<div class="hc-tabs" data-orientation="vertical"> <div class="hc-tabs__list" role="tablist" aria-orientation="vertical" aria-label="Workspace"> <button type="button" class="hc-tabs__tab" role="tab" …>Overview</button> <!-- … --> </div> <!-- panels --></div>installTabs() は aria-orientation を設定してくれますが、
JavaScript の実行前から向きが正しいよう、マークアップにも含めて
ください。縦方向とスクロール可能なオーバーフロー行は別のレイアウト
です — 組み合わせないでください。
URL ルーティングタブ
Section titled “URL ルーティングタブ”各タブが独自のルートである場合は、ARIA のタブ role を落とし、
ブラウザにマークアップを普通のナビゲーションとして扱わせます。
aria-current="page" がアクティブなタブに印を付けます。
installTabs() はこの変種を無視します。
<div class="hc-tabs"> <nav class="hc-tabs__list" aria-label="Documentation"> <a class="hc-tabs__tab" href="/docs/overview" aria-current="page">Overview</a> <a class="hc-tabs__tab" href="/docs/api">API</a> <a class="hc-tabs__tab" href="/docs/changelog">Changelog</a> </nav></div>htmx での利用
Section titled “htmx での利用”パネルが初めてアクティブになったときにコンテンツを取得するには、
hc:tabactivated — パネルが表示されたときにビヘイビアが発火する
イベント — を待ち受けます。
<div class="hc-tabs__panel" role="tabpanel" id="panel-billing" aria-labelledby="tab-billing" tabindex="0" hidden="until-found" data-hx-get="/account/billing" data-hx-trigger="hc:tabactivated once" data-hx-target="this" data-hx-swap="innerHTML"> <span class="hc-spinner" aria-hidden="true"></span></div>ページ内検索
Section titled “ページ内検索”非アクティブなパネルは hidden="until-found" を運ぶため、ブラウザの
Ctrl+F がその中を検索できます。ユーザーのクエリが隠れたパネル内の
テキストに一致するとブラウザが beforematch を発火し、ビヘイビアが
それを捕まえて所有タブへ自動で切り替え、一致箇所を見えるようにし
ます。hidden="until-found"の
ないブラウザは、この属性を素の hidden として扱います。
アクセシビリティ
Section titled “アクセシビリティ”- アプリ状態パターンは WAI-ARIA APG に従います。role:
tablist、tab、tabpanel。 - 各タブは自身のパネルを指す
aria-controlsを、各パネルは自身の タブを指し返すaria-labelledbyを必要とします。 - アクティブなタブは
aria-selected="true"とtabindex="0"を、 非アクティブなタブはaria-selected="false"とtabindex="-1"を 運びます(ロービングタブインデックスパターン)。無効なタブはaria-disabled="true"を使い、矢印ナビゲーションからスキップされ ます。 - tablist にはアクセシブルな名前が必須です。
[role="tablist"]要素にaria-labelまたはaria-labelledbyを使ってください。 - 縦の tablist は
aria-orientation="vertical"を運びます (installTabs()がdata-orientationから設定)。矢印キーの軸は それに従います — 縦なら ↑ / ↓、横なら ← / →。 - パネルはプログラム的にフォーカス可能(
tabindex="0")なので、 キーボードユーザーはTabでコンテンツへ直接入れます。 - URL ルーティング変種は、ナビゲーションのアクセシビリティをすべて
<nav>+<a>から継承します。そこに ARIA のタブ role を足さないで ください — ナビゲーションパターンと衝突します。
テーマ用トークン
Section titled “テーマ用トークン”component トークン(component.tokens.json):
| トークンパス | 用途 |
|---|---|
tabs.list.gap / list.border | タブ間のギャップと下枠線。 |
tabs.tab.height / padding-x | --hc-control-*(密度)を継承。 |
tabs.tab.fg / hover-fg / hover-bg / active-fg | タブのテキストとホバー面。 |
tabs.tab.indicator / indicator-size | アクティブ状態の下線。 |
tabs.tab.disabled-fg | aria-disabled="true" 時のタブテキスト。 |
tabs.pill.active-bg / active-fg | data-variant="pill" の塗り背景。 |
tabs.panel.padding-y / focus-ring | パネルの余白とフォーカスアウトライン。 |
tabs.sm.* / tabs.lg.* | 専用の sm / lg 上書き。 |
CSS 変数
Section titled “CSS 変数”生成される CSS 変数を表示
--hc-tabs-list-gap | -list-border--hc-tabs-tab-height | -padding-x | -font-size | -font-weight | -radius--hc-tabs-tab-fg | -hover-fg | -hover-bg | -active-fg--hc-tabs-tab-indicator | -indicator-size--hc-tabs-tab-disabled-fg--hc-tabs-pill-active-bg | -pill-active-fg--hc-tabs-panel-padding-y | -panel-focus-ring--hc-tabs-scroll-size /* width of the overflow scroll buttons; default 2rem */--hc-tabs-sm-tab-height | -sm-tab-padding-x | -sm-tab-font-size--hc-tabs-lg-tab-height | -lg-tab-padding-x | -lg-tab-font-size--hc-control-height (inherited from data-density)--hc-color-action-primary-bg | -primary-fg (inherited from data-color)--hc-color-focus-ringレシピでの利用: レイジーパネル