Skip to content
fandhe-frontendcore v0.4.3
GitHub

Drawer

画面端からスライドインするパネルです。ark-ui・chakra-ui の Drawer は WAI-ARIA 上 Dialog パターンの変種であり、fandhe-frontend-headless-ui の drawer mod は新規状態機械を作らず dialog mod の開閉状態機械をそのまま再利用します。追加する要素は専用 anatomy(data-scope="drawer")と、画面のどの端から出現するかを表す DrawerPlacement(Start/End/Top/Bottom、既定 End)のみです。content は tabindex="-1" を固定付与します(プログラム的フォーカスのみを許可する WAI-ARIA dialog パターンの前提)。

キーボード操作

fandhe-frontend-wasm-full は drawer scope を一切配線していません(trigger/close-trigger の click 配線・Escape/外側クリックでの閉鎖・フォーカストラップのいずれも未対応)。このためハイドレーション後もキーボード操作・クリック操作に応答せず、キーボード操作の表は現時点では提供しません(fail-closed のため未対応でも安全側です。別イシューで追跡します)。

参考サイトとの差分

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

  • grabber / grabber-indicator / swipe-area / indent / indent-background パーツ(zag のドラッグ・スタック積層 UI): ドラッグ操作・実行時計測に紐づく装飾関心のため不採用です(docs/policy/intentional-non-adoption.md §3.25 規則 2)。
  • data-swipe-direction / data-swiping / data-dragging / data-expanded / data-nested-drawer-*(zag のドラッグ・ネスト計測状態): 同様にドラッグ操作の実行時計測関心のため不採用です。data-placement(論理方向、RTL 対応)はこれらの物理方向語彙へ置き換えていません。
  • trigger の data-ownedby / data-value / data-current(zag の複数トリガー識別): aria-controls による id 関連付けが同等の役割を担うため不採用です(dialog と同判断)。
  • DOM 上の root パート: 全部品共通の規約(data-state の付与先)のため維持しています。
  • backdrop の aria-hidden="true": zag は付けませんが、装飾層として読み上げ対象外にする既存方針のため維持しています。
  • content の role="dialog" 固定(zag は alertdialog も選択可能): Drawer は確認・警告用途ではなく常設ナビ・フィルタ等の補助パネル用途に限定するため維持しています。
  • chakra-ui の Header / Body / Footer / ActionTrigger: fandhe-frontend-pre-styled-ui(Themes 層)の関心のため headless anatomy には持ち込みません。

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

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

自前 CSS の最小例

Themes 版を使わず本部品を直接使う場合、[data-scope="drawer"][data-part="..."] セレクタでスタイルを当てます。author スタイルの display が UA の [hidden] { display: none } を上書きして closed 状態が見えてしまわないよう、backdrop/positioner/content には [hidden] ガードを必ず含めます。[data-placement="..."] で 4 方向(start/end/top/bottom)ごとの配置・サイズを切り替えます。start/end は書字方向依存のため、物理方向(left/right)ではなく論理プロパティ(inset-inline-start 等)で書きます。

CSS
[data-scope="drawer"][data-part="backdrop"] {
  position: fixed;
  inset: 0;
  background: rgb(0 0 0 / 0.4);
}

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

[data-scope="drawer"][data-part="positioner"] {
  position: fixed;
  inset: 0;
}

[data-scope="drawer"][data-part="content"] {
  position: fixed;
  background: #fff;
  box-shadow: 0 0 1rem rgb(0 0 0 / 0.2);
}

[data-scope="drawer"][data-part="content"][data-placement="start"] {
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: 20rem;
  block-size: 100%;
}

[data-scope="drawer"][data-part="content"][data-placement="end"] {
  inset-block: 0;
  inset-inline-end: 0;
  inline-size: 20rem;
  block-size: 100%;
}

[data-scope="drawer"][data-part="content"][data-placement="top"] {
  inset-inline: 0;
  inset-block-start: 0;
  block-size: 20rem;
  inline-size: 100%;
}

[data-scope="drawer"][data-part="content"][data-placement="bottom"] {
  inset-inline: 0;
  inset-block-end: 0;
  block-size: 20rem;
  inline-size: 100%;
}

Demo

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

Features

  • dialog パターンの変種として crate::dialog の Disclosure 状態機械をそのまま再利用する(新規状態機械を作らない)。
  • DrawerPlacement(Start/End/Top/Bottom、既定 End)で画面のどの端から出現するかを切り替え、root/positioner/content の data-placement へ反映する。
  • content は role="dialog" を固定付与する(Alertdialog 相当の variant は提供しない。常設ナビ・フィルタ等の補助パネル用途に一致させるため)。
  • content は tabindex="-1" を固定付与する(zag drawer.connect.ts/WAI-ARIA dialog パターンの前提。イシュー #1639)。
  • fandhe-frontend-wasm-full は drawer scope を一切配線していない(MAPPING_TABLE に scope="drawer" の行がなく trigger/close-trigger の click が dispatch されない、OverlayKind::from_scope は "drawer" を拒否、focus_trap::should_trap も data-scope="dialog" のみ対象)。ハイドレーション後の Drawer は現状 inert であり、Escape/外側クリック閉鎖・フォーカストラップのいずれも未対応(別イシューで追跡、fail-closed のため未対応でも安全側。イシュー #1639 で判明・記述是正)。
  • grabber/swipe-area 等のドラッグ操作パーツ・data-swipe-direction 等のスワイプ状態語彙は意図的に非採用(ドラッグ操作という JS ランタイムの実行時計測関心のため。イシュー #1639)。

Anatomy

trigger
root
  backdrop
  positioner
    content
      title
      description
      close-trigger

API Reference

Arguments

NameTypeDefaultDescription
root: stateOpenStateClosedドロワー全体の開閉状態(data-state へ反映)。
root: placementDrawerPlacementEnd画面のどの端から出現するか(root/positioner/content の data-placement へ反映)。
trigger: stateOpenStateClosedaria-expanded/data-state へ反映される開閉状態。
trigger: controlsOption<&str>—Some のとき aria-controls で content と関連付ける。
backdrop: stateOpenStateClosedclosed のとき hidden 存在属性を付与する背面レイヤーの開閉状態。
positioner: stateOpenStateClosedclosed のとき hidden 存在属性を付与する配置ラッパーの開閉状態。
positioner: placementDrawerPlacementEnddata-placement へ反映される配置(styled 層が方向別レイアウトを切り替える起点)。
content: stateOpenStateClosed開閉状態(closed のとき hidden 存在属性を付与)。
content: placementDrawerPlacementEnddata-placement へ反映される配置。
content: modalbool—aria-modal へ反映する値。
content: idsContentIdsContentIds::default()content 自身の id・aria-labelledby・aria-describedby をまとめた構造体(crate::dialog の型を再利用)。
title: idOption<&str>—content の labelledby と対で aria-labelledby 関連付けを成立させる。
description: idOption<&str>—content の describedby と対で aria-describedby 関連付けを成立させる。
close_trigger_with_variant: variantCloseTriggerVariantIcondata-variant(icon/text)へ反映する見た目バリアント(イシュー #2193、dialog と対称)。fandhe-frontend-wasm-full が drawer scope を未配線のため、text variant を footer 相当のアクション行に置いても現状 inert(本節冒頭の記述参照)。

Data Attributes

PartAttributeObserved Values
backdropdata-stateopen
close-triggerdata-varianttext
contentdata-placementend
contentdata-stateopen
positionerdata-placementend
positionerdata-stateopen
rootdata-placementend
rootdata-stateopen
triggerdata-stateopen

Examples

Start placement

DrawerPlacement::Start(既定 End とは逆側)から出現するナビゲーション用ドロワーの例です。

Accessibility

WAI-ARIA

AttributeDescription
aria-haspopup="dialog"trigger に固定付与。
aria-expandedtrigger に付与。開閉状態を反映する。
aria-controlstrigger に付与。controls が Some のとき content と関連付ける。
aria-hidden="true"backdrop に固定付与(装飾層のため読み上げ対象外)。
role="dialog"content に固定付与(Alertdialog 相当の variant は提供しない)。
aria-modalcontent に付与。modal 引数の値を反映する。
aria-labelledby / aria-describedbycontent に付与。ids.labelledby/ids.describedby が Some のときのみ出力される。
tabindex="-1"content に固定付与。プログラム的フォーカスのみを許可する WAI-ARIA dialog パターンの前提(イシュー #1639)。