Skip to content
fandhe-frontendcore v0.4.3
GitHub

Popover

トリガー起点のオーバーレイです。fandhe-frontend-headless-ui の popover mod は Root / Trigger / Anchor / Positioner / Arrow / ArrowTip / Content / Title / Description / CloseTrigger / Indicator の 11 anatomy パーツを提供します。trigger は aria-haspopup="dialog"・aria-expanded・(controls が指定されたときの)aria-controls を持ち、content は role="dialog" を固定付与します。本部品は SSR での属性出力と状態機械のみを担い、trigger/close-trigger の click → dispatch 配線・Escape キーでの閉鎖・外側クリックでの閉鎖は fandhe-frontend-wasm-full が実 DOM 配線を担います。content は tabindex="-1" を固定付与します(プログラム的フォーカスのみを許可する WAI-ARIA dialog パターンの前提)。

キーボード操作

キー対象効果
Enter / SpaceTriggerポップオーバーを開きます(fandhe-frontend-wasm-full の headless part → action 対応表が "toggle" を dispatch)。
Enter / SpaceCloseTriggerポップオーバーを閉じます(同対応表が "close" を dispatch)。
Escape—最上位のポップオーバーを閉じます。data-close-on-escape="false" で無効化できます。
Tab / Shift+Tab—フォーカストラップはありません(通常の文書順でフォーカスが移動します)。参考サイト(ark-ui/Radix)の「Esc 後に trigger へフォーカスを復帰する」挙動は未実装です。

参考サイトとの差分

ark-ui・Radix Primitives・chakra-ui と突合し、content の tabindex="-1" 固定付与を追加しました。anatomy(11 パート)・data-* 語彙の増減はありません。一方、以下は意図的に合わせていません。

  • Radix Portal: DOM 配置の関心のため不採用です。
  • zag の data-placement: data-side/data-align(positioner へ付与)が同役割を担うため置き換えていません。
  • zag の data-expanded(content): data-state + aria-expanded と重複するため不採用です。
  • zag の trigger data-ownedby / data-value / data-current(複数トリガー識別): aria-controls による id 関連付けが同等の役割を担うため不採用です(dialog と同判断)。
  • chakra-ui の Header / Body / Footer: fandhe-frontend-pre-styled-ui(Themes 層)の関心のため headless anatomy には持ち込みません。
  • close-trigger の既定 aria-label: アイコンボタン等の用途を想定し、内容を強制しない既存方針のため呼び出し側の責務のまま維持しています。
  • フォーカストラップ・開時の autoFocus・閉鎖時の trigger へのフォーカス復帰: 参考サイトは Esc 後に trigger へフォーカスを復帰させますが、本リポジトリでは未実装です(focus_trap::should_trap は dialog scope のみを対象とします)。

スタイル済みの表示例は Popover を参照してください。

関連 API: fandhe-frontend-headless-ui API

自前 CSS の最小例

Themes 版を使わず本部品を直接使う場合、[data-scope="popover"][data-part="..."] セレクタでスタイルを当てます。author スタイルの display が UA の [hidden] { display: none } を上書きして closed 状態が見えてしまわないよう、positioner/content には [hidden] ガードを必ず含めます。

CSS
[data-scope="popover"][data-part="root"] {
  position: relative;
  display: inline-block;
}

[data-scope="popover"][data-part="positioner"] {
  position: absolute;
  top: 100%;
  left: 0;
}

[data-scope="popover"][data-part="positioner"][hidden],
[data-scope="popover"][data-part="content"][hidden] {
  display: none;
}

[data-scope="popover"][data-part="content"] {
  background: #fff;
  border: 1px solid rgb(0 0 0 / 0.1);
  border-radius: 8px;
  padding: 1rem;
  box-shadow: 0 0.25rem 1rem rgb(0 0 0 / 0.15);
}

[data-scope="popover"][data-part="arrow"] {
  position: absolute;
  width: 0.5rem;
  height: 0.5rem;
}

Demo

枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。

Features

  • Root / Trigger / Anchor / Positioner / Arrow / ArrowTip / Content / Title / Description / CloseTrigger / Indicator の 11 anatomy パーツと、Disclosure を埋め込んだ開閉状態機械 Popover を提供する。
  • trigger は type="button" を固定付与し、aria-haspopup="dialog"・aria-expanded・(controls が Some のとき)aria-controls を持つ。
  • content は role="dialog" を固定付与し、labelledby/describedby が Some のときのみ title/description と対で関連付ける。content は tabindex="-1" を固定付与する(zag popover.connect.ts と同じく、プログラム的フォーカスのみを許可する前提。イシュー #1642)。
  • trigger/close-trigger の click → dispatch 配線("toggle"/"close")、Escape・外側クリックでの閉鎖は fandhe-frontend-wasm-full(headless の part → action 対応表・overlay モジュール)が実 DOM 配線を担う。content の attrs 経由で data-close-on-escape="false" / data-close-on-interact-outside="false"("false" リテラルのときのみ無効化)を渡せる。フォーカストラップ・開時の autoFocus・閉鎖時の trigger へのフォーカス復帰は未実装である(focus_trap::should_trap は data-scope="dialog" のみを対象とし popover を含まない、イシュー #1642 で判明)。

Anatomy

root
  trigger
  anchor
  positioner
    content
      arrow
        arrow-tip
      title
      description
      close-trigger
      indicator

API Reference

Arguments

NameTypeDefaultDescription
root: stateOpenStateClosed開閉状態(data-state へ反映)。
trigger: stateOpenStateClosedaria-expanded/data-state へ反映される開閉状態。
trigger: disabledbool—ネイティブ disabled 存在属性と data-disabled の両方へ反映する disabled 状態。
trigger: controlsOption<&str>—Some のとき aria-controls で content と関連付ける。
positioner: stateOpenStateClosedclosed のとき hidden 存在属性を付与する配置ラッパーの開閉状態。
content: stateOpenStateClosed開閉状態(closed のとき hidden 存在属性を付与)。
content: idOption<&str>—trigger の controls と対で aria-controls 関連付けを成立させる。
content: labelledbyOption<&str>—Some のとき title の id と対で aria-labelledby 関連付けを成立させる。
content: describedbyOption<&str>—Some のとき description の id と対で aria-describedby 関連付けを成立させる。
title: idOption<&str>—content の labelledby と対にする。
description: idOption<&str>—content の describedby と対にする。
indicator: stateOpenStateClosed開閉状態のみを data-state へ反映する最小主義な装飾用パーツ。

Data Attributes

PartAttributeObserved Values
contentdata-stateclosed, open
indicatordata-stateclosed, open
positionerdata-stateclosed, open
rootdata-stateclosed, open
triggerdata-disabled(値なし)
triggerdata-stateclosed, open

Examples

Minimal content

title/description を持たず close_trigger のみを含む、最小構成の Popover content の例です。

Accessibility

Keyboard Interactions

KeyDescription
Enter / Space (trigger)ネイティブ button 要素の click 相当が成立し、fandhe-frontend-wasm-full の headless part → action 対応表が "toggle" を dispatch する。
Enter / Space (close-trigger)同対応表が "close" を dispatch する。
Escapeoverlay::close_on_escape_for が最上位オーバーレイに "close" を通知する(push_overlay の登録と実際の dispatch は #580 統合層の責務)。data-close-on-escape="false" で無効化できる。
Tab / Shift+Tabフォーカストラップは無い(focus_trap::should_trap は data-scope="dialog" のみを対象とし popover は含まない)。通常の文書順でフォーカスが移動する。

WAI-ARIA

AttributeDescription
aria-haspopup="dialog"trigger に固定付与。
aria-expandedtrigger に付与。開閉状態を反映する。
aria-controlstrigger に付与。controls が Some のとき content と関連付ける。
role="dialog"content に固定付与。
aria-labelledby / aria-describedbycontent に付与。labelledby/describedby が Some のときのみ出力される。
tabindex="-1"content に固定付与。プログラム的フォーカスのみを許可する(イシュー #1642)。