Hover Card
リンク先プレビュー等、hover / focus で開閉するオーバーレイです。fandhe-frontend-headless-ui の hover_card mod は Root / Trigger / Positioner / Content / Arrow / ArrowTip の 6 anatomy パーツを提供します。trigger はリンク先プレビュー用途の a 要素であり、HoverCardDelays(open_ms/close_ms、ark-ui 既定の 600/300 ms)を data-open-delay/ data-close-delay として決定的に出力します。WAI-ARIA に hover card 専用パターンは存在しないため、aria-expanded/aria-controls/aria-haspopup 及び固定 role を一切付与しません(Tooltip との違い)。
キーボード操作
| キー | 対象 | 効果 |
|---|---|---|
| Tab | Trigger | trigger はネイティブ a 要素のため、href を渡している場合はブラウザ標準でフォーカス到達します。Radix の「Tab で hover card を開閉」に相当する focus/blur 駆動の開閉配線は fandhe-frontend-wasm-full 側の責務で未配線です。 |
| Enter | Trigger | href を渡している場合、リンク先へ遷移します(ブラウザ標準)。hover card 自体の開閉はこのキー操作では行いません。 |
参考サイトとの差分
Zag.js(hover-card.connect.ts)・ark-ui・Radix Primitives・Radix Themes・chakra-ui と突合し、是正すべき欠落は見つかりませんでした(イシュー #1641)。anatomy(6 パート)・data-state 語彙(open/closed)・ARIA 非付与方針はいずれも一致しています。一方、以下は意図的に合わせていません。
data-side/data-alignの付与先: Radix はcontentへ、Zag はtrigger/contentの双方へ出しますが、本クレートはpositioning(#590)の規約どおりpositionerへ透過させます(Tooltip/Popover と同型。hover-card だけ変えると規約が分裂するため)。tabindex="-1"(content)・dir・自動id(Zag): hover/focus のタイマー・DOM 配線がfandhe-frontend-wasm-fullに未実装の段階では固定付与しません。- 複数トリガー識別(
data-value/data-current/data-ownedby、Zag): 機能拡張でありスコープ外候補です(下記参照)。
上記の差分に伴う data-*・パートの増減は無いため、Themes 側イシュー #1523(closed)への追加コメントは行っていません。
スコープ外候補(是正対象ではなく、別途起票を検討する余地がある事項):
- 複数トリガー対応(Zag の
data-value/data-current/data-ownedby) fandhe-frontend-wasm-full側の hover/focus タイマー配線・PositionedKind::from_scope("hover-card")への追加- 配線後の content
tabindex="-1"付与の再評価
スタイル済みの表示例は Hover Card を参照してください。
関連 API: fandhe-frontend-headless-ui API
自前 CSS の最小例
[data-scope="hover-card"][data-part="..."] セレクタでスタイルを当てます。以下は content の枠・影、closed 時の非表示、trigger のフォーカスリング、positioner の配置調整の最小例です。
[data-scope="hover-card"][data-part="content"] {
border: 1px solid #888;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
[data-scope="hover-card"][data-part="content"][data-state="closed"] {
display: none;
}
[data-scope="hover-card"][data-part="trigger"]:focus-visible {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
[data-scope="hover-card"][data-part="positioner"][data-side="top"] {
margin-bottom: 8px;
}Demo
枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。
Features
- Root / Trigger / Positioner / Content / Arrow / ArrowTip の 6 anatomy パーツと、Disclosure を埋め込んだ開閉状態機械 HoverCard を提供する。trigger はリンク先プレビュー用途の a 要素であり、Tooltip とはこの点が異なる。
- HoverCardDelays(open_ms 既定 600 / close_ms 既定 300、ark-ui 既定値)を data-open-delay/data-close-delay(10 進の ms 値のみ)として決定的に出力する。実際の hover/focus タイマー駆動は wasm-full 側の責務でスコープ外。
- WAI-ARIA に hover card 専用パターンが存在しないため、aria-expanded/aria-controls/aria-haspopup 及び content への固定 role を一切付与しない(Tooltip/Popover との違い)。
- ark-ui の Root > Trigger > Positioner > (Arrow > ArrowTip) + Content の 6 パートと完全一致(イシュー #1641 で Zag.js
hover-card.connect.ts・Radix Primitives と突合、是正なし)。data-side/data-align は positioner へ透過させる(tooltip/popover と同型の positioning 規約、#590)。
Anatomy
root
trigger
positioner
content
arrow
arrow-tipAPI Reference
Arguments
| Name | Type | Default | Description |
|---|---|---|---|
root: state | OpenState | Closed | 開閉状態(data-state へ反映)。 |
root: delays | HoverCardDelays | HoverCardDelays::default()(open_ms: 600, close_ms: 300) | data-open-delay/data-close-delay(10 進の ms 値のみ)へ反映される遅延設定。 |
trigger: state | OpenState | Closed | data-state へ反映される開閉状態。 |
trigger: href | Option<&str> | — | Some のときのみ href 属性を出力する(リンク先プレビュー用途)。 |
positioner: state | OpenState | Closed | closed のとき hidden 存在属性を付与する配置ラッパーの開閉状態。 |
content: state | OpenState | Closed | 開閉状態(closed のとき hidden 存在属性を付与)。 |
content: id | Option<&str> | — | 呼び出し側が任意に使える id(本モジュールは固定の aria-describedby を配線しない)。 |
Data Attributes
| Part | Attribute | Observed Values |
|---|---|---|
content | data-state | open |
positioner | data-state | open |
root | data-close-delay | 300 |
root | data-open-delay | 600 |
root | data-state | open |
trigger | data-state | open |
Examples
Custom delays
open_ms/close_ms を既定値(600/300)から変更し、開くまでの遅延を短く・閉じるまでの遅延を長くした例です。
Custom CSS
data-scope / data-part / data-state / data-side セレクタで自前 CSS を当てる最小例です。
利用者が data-scope / data-part / data-state / data-side セレクタで自前 CSS を当てる最小例です。headless-ui 自体はスタイルを持ちません。
[data-scope="hover-card"][data-part="content"] {
border: 1px solid #888;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
[data-scope="hover-card"][data-part="content"][data-state="closed"] {
display: none;
}
[data-scope="hover-card"][data-part="trigger"]:focus-visible {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
[data-scope="hover-card"][data-part="positioner"][data-side="top"] {
margin-bottom: 8px;
}
Accessibility
Keyboard Interactions
| Key | Description |
|---|---|
| Tab | trigger はネイティブ a 要素(hover_card.rs:150-162)のため、href が Some のときブラウザ標準でフォーカス到達する。Radix の「Tab で hover card を開閉」に相当する focus/blur 配線は fandhe-frontend-wasm-full 側の責務で未配線。 |
| Enter | href が Some の trigger でリンク先へ遷移する(ブラウザ標準)。hover card 自体の開閉はこのキー操作では行わない。 |
WAI-ARIA
| Attribute | Description |
|---|---|
| aria-expanded / aria-controls / aria-haspopup(非付与) | WAI-ARIA に hover card 専用パターンが無いため、trigger には付与しない(Zag.js hover-card.connect.ts・Radix Primitives とも一致、イシュー #1641 突合)。 |
| role(非付与) | content にも固定 role を付与しない(Zag.js・Radix とも一致)。Radix の Accessibility 注記: hover card は視覚ユーザー向けであり、content はキーボードユーザーには(フォーカス配線が無い限り)到達不能。 |
| aria-hidden="true" | arrow/arrow_tip に固定付与(装飾用のみ、スクリーンリーダーの読み上げ対象外)。 |