メニューボタン
stimeo--menu
コマンドを並べる本物のメニュー。矢印キーで項目を渡り歩けます。開閉だけの dropdown とは別物です。
ボタンから開くコマンドのメニューです。WAI-ARIA の Menu Button パターンの実装で、矢印キーで項目を渡り歩き、Home と End で両端へ飛べます。Esc、Tab、外側のクリック、項目の実行で閉じます。使えない項目の扱いは 2 通りです。完全に無効な項目は矢印キーの移動先から外れ、無効だと伝えたい項目はフォーカスは当たるが実行はされません。クリックもキーもメニュー全体で受けるので、項目ごとの設定は要らず、あとから足した項目もそのまま動きます。位置はこのデモの CSS で決めています。
キーボード操作
| キー | 動作 |
|---|---|
| Enter / Space / ↓ | メニューを開き、最初の項目にフォーカスする。 |
| ↑ | メニューを開き、最後の項目にフォーカスする。 |
| ↓ / ↑ | 項目間でフォーカスを移動する(末尾で循環)。 |
| Home / End | 最初 / 最後の項目にフォーカスする。 |
| 項目上の Enter / Space | 有効な項目を実行する。aria-disabled の項目は実行しない。 |
| Esc | メニューを閉じ、フォーカスをトリガーへ戻す。 |
<%# Markup for the menu (APG Menu Button) demo.
stimeo--menu is a full role="menu"/"menuitem" menu providing arrow-key roving
focus, Esc, and outside click (distinct from the disclosure dropdown).
Positioning (static placement) is the Playground's CSS. %>
<div class="menu" data-controller="stimeo--menu">
<button
id="menu-trigger"
type="button"
class="demo-trigger"
aria-haspopup="menu"
aria-expanded="false"
aria-controls="menu-list"
data-stimeo--menu-target="trigger"
data-action="click->stimeo--menu#toggle keydown->stimeo--menu#onTriggerKeydown">
<%= t("components.menu.demo.trigger") %>
</button>
<%# The trigger labels the menu; each item is a role="menuitem" button (tabindex=-1).
Items need no data-action: the controller handles their clicks and keys from its own
element, so items added or moved in later work without being wired up. %>
<ul id="menu-list" class="menu__list" role="menu" aria-labelledby="menu-trigger"
data-stimeo--menu-target="menu" hidden>
<li role="none">
<button type="button" role="menuitem" class="demo-menuitem" tabindex="-1"
data-stimeo--menu-target="item"><%= t("components.menu.demo.edit") %></button>
</li>
<li role="none">
<button type="button" role="menuitem" class="demo-menuitem" tabindex="-1"
data-stimeo--menu-target="item"><%= t("components.menu.demo.duplicate") %></button>
</li>
<li role="none">
<button type="button" role="menuitem" class="demo-menuitem" tabindex="-1"
data-stimeo--menu-target="item"><%= t("components.menu.demo.delete") %></button>
</li>
</ul>
</div>
/*
* Presentation-only styles for the menu (Menu Button) demo.
* This demo uses static CSS placement below the trigger. Consumers that need
* viewport-aware collision handling can compose the menu with the opt-in
* stimeo-ui/positioning entrypoint.
*/
.menu {
position: relative;
display: inline-block;
}
.menu__list {
position: absolute;
left: 0;
margin: 0.25rem 0 0;
padding: 0.25rem;
list-style: none;
min-width: 12rem;
background: var(--surface-card);
border: 1px solid var(--border-strong);
border-radius: 0.375rem;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
このデモに固有の消費側 JS はありません(挙動はコントローラが担います)。
これらのスタイルは共通のデザイントークン(ライト/ダーク両対応)を使います。共通スタイルも一緒にコピーし、ルート要素の data-theme を切り替えればダークになります。
このコンポーネントを動かすために HTML へ記述する data-* 属性です。ルート要素に下の data-controller を付け、その内側に各 target / value / action を配置します。
ルート要素に付与
data-controller="stimeo--menu"
ターゲット
| 名前 | 説明 | 属性 |
|---|---|---|
trigger
必須
|
メニューを開閉するボタン。aria-haspopup/aria-expanded を持ち、閉じるとフォーカスが戻る。 |
data-stimeo--menu-target="trigger" |
menu
必須
|
hidden で表示制御する名前付きの role="menu" 要素。aria-labelledby でトリガーを参照するか、aria-label を付与する。 |
data-stimeo--menu-target="menu" |
item
|
ロービングフォーカスを持つ role="menuitem" コマンド。aria-disabled=true の項目はスキップされ実行できない。 |
data-stimeo--menu-target="item" |
アクション
| 名前 | 説明 | アクション |
|---|---|---|
activate
|
有効な項目の実行後にメニューを閉じ、フォーカスをトリガーへ戻す。aria-disabled の実行は抑止する。 | stimeo--menu#activate |
close
|
メニューを閉じ、トリガーに折りたたみ状態を反映する。 | stimeo--menu#close |
onItemKeydown
|
メニュー内のロービングフォーカスと閉じるキー。矢印キー(循環)、Home/End、Escape(閉じてトリガーへ)、Tab(閉じる)。 | stimeo--menu#onItemKeydown |
onTriggerKeydown
|
キーボードでトリガーからメニューを開く。ArrowDown で先頭、ArrowUp で末尾の項目にフォーカス。 | stimeo--menu#onTriggerKeydown |
open
|
メニューを開き、トリガーに展開状態を反映する。 | stimeo--menu#open |
toggle
|
メニューを開閉する。開くときは先頭の項目にフォーカスする。 | stimeo--menu#toggle |
状態フック
ライブラリが操作するのはこれらの ARIA / data 属性、カスタムプロパティだけです。見た目は利用側 CSS がこれらに反応して作ります([aria-selected] / [aria-expanded] / var(--stimeo--…) などのセレクタでフックします)。
| フック | 対象 | 意味 |
|---|---|---|
aria-expanded |
トリガー | メニューが開いている間は "true"、閉じると "false"。 |
hidden |
メニュー | 開くと外れ、閉じると付与される。 |