Link Overlay
カード全体をクリック可能にする(カード全面クリック化)ための部品です。fandhe-frontend-headless-ui の link_overlay mod が構造・アクセシビリティ(WAI-ARIA・キーボード操作)・表示状態(data-*)のみを提供する unstyled 部品であり、Themes 版と異なりスタイル(CSS)は一切持ちません。root(div、位置決めコンテキスト)/ overlay(a、カード全面へ拡張されるリンク)の 2 パーツ構成で、overlay パーツを root 全面へ展開するのは呼び出し側の CSS(position: absolute; inset: 0;)の責務です。
スタイル済みの表示例は Link Overlay を参照してください。
キーボード操作
| キー | 対象 | 効果 |
|---|---|---|
| Tab / Shift+Tab | Overlay | ネイティブ a[href] へのフォーカス移動です(ブラウザ既定、headless-ui 側の配線なし)。root 内に内側リンクを併置する場合、フォーカス順は DOM 順に従います。 |
| Enter | Overlay | ネイティブ a[href] の起動(遷移)です。Space はリンクを起動しません(<a> 要素は Space キーでは発火しないブラウザ標準挙動です)。 |
参考サイトとの差分
参照実体は chakra-ui の LinkBox/LinkOverlay のみです。ark-ui の link-overlay ページは 404 で実在せず、Radix Primitives・Radix Themes にも対応部品がありません。chakra-ui の LinkBox/LinkOverlay は Anatomy 節・Keyboard Interactions 節・data-* 語彙・独自 ARIA 付与のいずれも持たない styled 部品です。本実装は以下の点で意図的に差分を残しています。
data-scope/data-part: 参考サイトには anatomy の概念自体が無く、本実装のこれらの属性はこちら側の superset です。- 状態
data-*の非出力:data-state/data-disabled/data-motion等の状態を表すdata-*は一切出力しません。参考サイトも同様に状態data-*を持ちません。 - 非対応の prop:
external(旧isExternal。現行 chakra-ui v3 docs では既に削除済み)・asChild(Slot 相当)は非対応です。externalは位置引数追加が破壊的変更になり呼び出し元全体へ波及するため追加せず、target/relを付与する場合は呼び出し側がattrsで両方を同時に渡す運用とします(link::rootの不可分保証は本部品には及びません)。asChildは headless-ui 全体での再導入検討事項(保留)です。 - 内側リンクの前面化: chakra-ui の
LinkBoxは CSS の子孫セレクタで内側リンクをoverlayより前面化しますが、headless 層は CSS を持たないため利用者側 CSS の責務です(下記の自前 CSS 例を参照)。 hrefの予約キー除去:overlayの呼び出し側attrsにhrefを渡しても、固定付与された正規hrefのみが出力されます(同名属性のなりすまし・二重出力の防止)。
一方で「role/aria-* を独自付与しない(暗黙の link ロールに委ねる)」点は参考サイトと一致しています。危険な URL スキーム(javascript: 等)は href 属性ごと拒否され、href を失った a はフォーカス不能になり暗黙の link ロールも失います(fail-closed の意味論的帰結)。overlay が root 全面へ absolute 展開されるため、root 内のテキストをポインタで選択しにくくなる点も参考サイトと同様です。
関連 API: fandhe-frontend-headless-ui API
自前 CSS の最小例
Themes 版を使わず本部品を直接使う場合、[data-scope="link-overlay"][data-part="root"|"overlay"] セレクタで root の位置決め・overlay の全面展開・内側リンクの前面化を組み立てます。
[data-scope="link-overlay"][data-part="root"] {
position: relative;
}
[data-scope="link-overlay"][data-part="overlay"] {
position: absolute;
inset: 0;
z-index: 0;
}
[data-scope="link-overlay"][data-part="overlay"]:focus-visible {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
[data-scope="link-overlay"][data-part="root"] a[href]:not([data-part="overlay"]) {
position: relative;
z-index: 1;
}Demo
枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。
Features
- カード全面クリック化。root(div、位置決めコンテキスト)/ overlay(a、カード全面へ拡張されるリンク)の 2 パーツ構成(chakra-ui LinkBox/LinkOverlay パターン相当、link_overlay.rs モジュール doc)。
- ::before 疑似要素を使わず、overlay 自身を position: absolute; inset: 0; で root 全面へ展開する方式を採る(styled 層の CSS 責務、headless 層は CSS を持たない)。
- overlay がフローから外れるため、root の高さは overlay 以外の子ノード(見出し・説明文等の通常フロー要素)が確立する契約である(module doc「全面拡張の実装方針」)。
- 単一リンクのみの overlay へ可視テキストを渡す代わりに、見出しを root の他の子ノードとして描画し overlay へは aria-label 等でアクセシブルネームのみを与える運用が推奨される。
- data-state/data-disabled/data-motion 等の状態 data-* は出力しない(参考サイト〔chakra-ui〕も同様に状態 data-* を持たない、§3.25 規則 2: 装飾・アニメーション関心を headless へ持ち込まない)。
- 参考サイト(chakra-ui LinkBox/LinkOverlay)は Anatomy/Keyboard/data-* 節を持たず、data-scope/data-part は本実装の superset。ark-ui・Radix Primitives・Radix Themes に対応部品なし。
- external(旧 isExternal)・asChild は非提供(意図的差分)。target/rel を attrs 経由で渡す場合は両方を同時に付与する運用を利用者側で行う(link::root の不可分保証は本部品には及ばない)。
- 内側リンクの前面化(chakra-ui の LinkBox が子孫セレクタで行う挙動)は headless 層が CSS を持たないため利用者 CSS の責務(自前 CSS 例を参照)。
- overlay の DOM 位置がタブ順を決める(chakra-ui はタイトル位置に置く運用を推奨)。
- 呼び出し側 attrs の href は予約キーとして除去される(同名なりすましの二重出力防止、イシュー #1650)。
Anatomy
root
overlayAPI Reference
Arguments
| Name | Type | Default | Description |
|---|---|---|---|
overlay(href) | &str | — | 遷移先 URL。危険な URL スキームは core の render() が属性ごと拒否する。 |
Examples
見出しを別描画し overlay へ aria-label のみ与える構成
module doc が推奨する運用(可視見出しは root の子として描画し、overlay へはアクセシブルネームのみを渡す)を実演します。
タイトル + 説明文 + 内側リンクの構成(chakra-ui パターン)
参考サイト(chakra-ui LinkBox/LinkOverlay)の典型構成(タイトル位置の overlay・説明文・内側の通常リンク)を実演します。
Highlights from the latest release, including breaking changes.
自前 CSS の最小例
data-scope/data-part 属性セレクタで root の位置決め・overlay の全面展開・内側リンクの前面化を組み立てる最小例です。headless-ui 自体はスタイルを持ちません。
[data-scope="link-overlay"][data-part="root"] {
position: relative;
}
[data-scope="link-overlay"][data-part="overlay"] {
position: absolute;
inset: 0;
z-index: 0;
}
[data-scope="link-overlay"][data-part="overlay"]:focus-visible {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
[data-scope="link-overlay"][data-part="root"] a[href]:not([data-part="overlay"]) {
position: relative;
z-index: 1;
}
Accessibility
Keyboard Interactions
| Key | Description |
|---|---|
| Tab / Shift+Tab | ネイティブ a[href](overlay パーツ)由来のフォーカス移動。headless-ui 側の配線なし。root 内に内側リンクを併置する場合、フォーカス順は DOM 順に従う。 |
| Enter | フォーカス中の overlay(a)をブラウザ既定動作で遷移する。Space は起動しない(ブラウザ既定の a 要素の挙動)。 |
WAI-ARIA
| Attribute | Description |
|---|---|
| role / aria-* | 既定では独自付与しない。暗黙の link ロールに委ねる(参考サイト〔chakra-ui〕も独自付与しない)。 |
| aria-label | overlay 自身は aria-label を自動付与しない。単一リンクのみで完結する構成では呼び出し側が attrs 経由でアクセシブルネームを与える運用が推奨される(module doc 参照)。 |
| (危険スキーム時) | javascript: 等の危険な URL スキームは core の render() が href 属性ごと拒否する。href を失った a はフォーカス不能になり、暗黙の link ロールも失う(fail-closed の意味論的帰結)。 |
| (ポインタ操作の注記) | overlay が root 全面へ absolute 展開されるため、root 内のテキストをポインタで選択しにくくなる(参考サイト〔chakra-ui〕にも同様の注記がある)。 |