ディスミッシブル
stimeo--dismissible
バナーやお知らせを、フォーカスを宙に浮かせずに閉じる。
stimeo--dismissible コントローラは、閉じるボタン(または closeOnEscape 有効時は Escape)で要素を消去(remove)または非表示(hide)にします。アクセシビリティ上の役割はフォーカスの安全確保です。消去対象の内側にフォーカスがある場合は、fallback ターゲット → 次のフォーカス可能要素 → 前のフォーカス可能要素 → document.body の順で退避させ、閉じるボタンが消えてもフォーカスが宙に浮かないようにします。消去時には dismiss イベントが mode を載せて発火します。ライブラリは挙動のみを提供し、出入りアニメーションや role="alert" などの意味付けは利用側の責務です。
キーボード操作
| キー | 動作 |
|---|---|
| Enter / Space | 閉じるボタンを実行(ネイティブボタン)。 |
| Escape | closeOnEscape 有効かつフォーカスが内側のとき消去。 |
<%# Markup for the dismissible (element dismissed via a close button) demo.
The close button (or Escape) removes the element, and if focus was inside before
removal it is moved to a safe place (fallback → next/previous focusable → body).
Here it uses hide mode (adds hidden) and allows closing with Escape too.
Semantics like role="status" are the consumer markup's responsibility. %>
<div
class="dismissible"
data-controller="stimeo--dismissible"
data-stimeo--dismissible-mode-value="hide"
data-stimeo--dismissible-close-on-escape-value="true">
<div
class="dismissible__banner"
role="status"
data-stimeo--dismissible-target="root">
<span class="dismissible__icon" aria-hidden="true">✓</span>
<p class="dismissible__message"><%= t("components.dismissible.demo.message") %></p>
<button
class="dismissible__close"
type="button"
aria-label="<%= t('components.dismissible.demo.close') %>"
data-action="click->stimeo--dismissible#dismiss">
<span aria-hidden="true">×</span>
</button>
</div>
<a class="dismissible__after" href="#" data-stimeo--dismissible-target="fallback">
<%= t("components.dismissible.demo.fallback") %>
</a>
</div>
/*
* Presentation-only styles for the dismissible demo.
* Dismissal is expressed via hide mode (the library adds hidden to the root).
*/
.dismissible {
display: flex;
flex-direction: column;
gap: 0.5rem;
max-width: 32rem;
}
.dismissible__banner {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1rem;
border: 1px solid var(--leaf-50);
border-radius: 0.5rem;
background: var(--leaf-50);
color: var(--leaf-500);
}
.dismissible__icon {
font-weight: 700;
}
.dismissible__message {
margin: 0;
flex: 1;
}
.dismissible__close {
display: grid;
place-items: center;
width: 1.75rem;
height: 1.75rem;
border: 0;
border-radius: 0.25rem;
background: transparent;
color: inherit;
font-size: 1.25rem;
line-height: 1;
cursor: pointer;
}
.dismissible__close:hover {
background: var(--leaf-50);
}
.dismissible__after {
align-self: flex-start;
font-size: 0.875rem;
color: var(--accent);
}
このデモに固有の消費側 JS はありません(挙動はコントローラが担います)。
これらのスタイルは共通のデザイントークン(ライト/ダーク両対応)を使います。 共通スタイルも一緒にコピーし、ルート要素の data-theme を切り替えればダークになります。
このコンポーネントを動かすために HTML へ記述する data-* 属性です。ルート要素に下の data-controller を付け、その内側に各 target / value / action を配置します。
ルート要素に付与
data-controller="stimeo--dismissible"
ターゲット
| 名前 | 説明 | 属性 |
|---|---|---|
root
|
解除対象の要素。省略時はホスト要素にフォールバックする。 | data-stimeo--dismissible-target="root" |
fallback
|
解除によって root 内のフォーカスが宙に浮くとき、優先的にフォーカスを移す要素。 | data-stimeo--dismissible-target="fallback" |
値(Values)
| 名前 | 説明 | 属性 |
|---|---|---|
mode
|
解除方法。remove で DOM から削除(既定)、hide で hidden を付与。 |
data-stimeo--dismissible-mode-value |
closeOnEscape
|
true のとき、内部にフォーカスがある状態で Escape を押すと解除する(既定 false)。 | data-stimeo--dismissible-close-on-escape-value |
アクション
| 名前 | 説明 | アクション |
|---|---|---|
dismiss
|
必要に応じてフォーカスを退避し、mode に従って要素を削除または非表示にする。 | stimeo--dismissible#dismiss |
イベント
| 名前 | 説明 | イベント |
|---|---|---|
dismiss
|
削除・非表示の直前に同期的に発火。detail に解決済みの { mode } を載せる。 |
stimeo--dismissible:dismiss |
状態フック
ライブラリが操作するのはこれらの ARIA / data 属性、カスタムプロパティだけです。見た目は利用側 CSS がこれらに反応して作ります([aria-selected] / [aria-expanded] / var(--stimeo--…) などのセレクタでフックします)。
| フック | 対象 | 意味 |
|---|---|---|
hidden |
root | hide モードでの消去時に付与(remove モードは DOM ごと除去)。 |
data-state |
root | "open" / "closing"。出去アニメーションの起点(任意)。 |