サイドバー
stimeo--sidebar
レスポンシブな折りたたみサイドバー。ブレークポイント未満ではモーダルなオフキャンバスに変化するインラインのレール。
stimeo--sidebar コントローラに専用の APG パターンはない。土台は Disclosure (トリガーの aria-expanded で領域の表示を制御)で、ブレークポイント未満では Dialog (Modal) のフォーカス挙動を共有 FocusTrap(dialog / alert-dialog / drawer と同じトラップ)経由で借りる。ブレークポイント以上では非モーダルのインラインなレールとして expanded/collapsed を切り替え、その設定を localStorage に永続化する。未満ではオーバーレイのオフキャンバスに変化し、開くとフォーカスを内側へ移し、Tab を循環させ、背景スクロールをロックし、背景を inert にする。Escape かバックドロップのクリックで閉じ、フォーカスを復帰する。role="dialog" はあえて付けず、ランドマークは aside/nav のままにする。デモを 600px 未満に狭めるとオーバーレイモードを確認できる。ライブラリは振る舞いのみを提供し、レール幅・スライド・バックドロップは Playground の CSS が持つ。
キーボード操作
| キー | 動作 |
|---|---|
| Esc | (ブレークポイント未満の)オーバーレイを閉じ、フォーカスをトリガーへ戻す。 |
| Tab / Shift+Tab | オーバーレイが開いている間、パネル内でフォーカスを循環(トラップ)。 |
<%# Markup for the sidebar (collapsible sidebar) demo.
This demo focuses on the INLINE rail: the toggle collapses / expands it and the
preference persists in localStorage across reloads. (The same sidebar can also
switch to a modal off-canvas panel below a breakpoint — that document-level modal
mode is described in the text and is the same off-canvas pattern the Drawer demo
shows; it is not staged here because a page-level modal inside a catalog card reads
as taking over the page.) breakpoint=0 keeps this demo always inline. The library
syncs aria-expanded, data-mode, and data-state; the rail width / animation are
demo.css's. role="dialog" is intentionally not applied — the panel stays a nav. %>
<div
class="sidebar-demo"
data-controller="stimeo--sidebar"
data-stimeo--sidebar-breakpoint-value="0"
data-stimeo--sidebar-key-value="catalog-demo">
<div class="sidebar-demo__bar">
<button
type="button"
class="sidebar-demo__toggle"
data-stimeo--sidebar-target="trigger"
data-action="click->stimeo--sidebar#toggle"
aria-expanded="true"
aria-controls="sidebar-demo-panel">
<%= t("components.sidebar.demo.toggle") %>
</button>
<span class="sidebar-demo__brand"><%= t("components.sidebar.demo.brand") %></span>
</div>
<div class="sidebar-demo__body">
<nav
id="sidebar-demo-panel"
class="sidebar-demo__panel"
data-stimeo--sidebar-target="panel"
aria-label="<%= t('components.sidebar.demo.nav_label') %>"
data-mode="inline"
data-state="expanded">
<% t("components.sidebar.demo.items").each do |label| %>
<a class="sidebar-demo__link" href="#"><%= label %></a>
<% end %>
</nav>
<main class="sidebar-demo__content">
<p><%= t("components.sidebar.demo.hint") %></p>
</main>
</div>
</div>
/*
* Presentation-only styles for the sidebar demo (inline rail).
* Stimeo ships behavior only: the library syncs aria-expanded, data-mode, and
* data-state (expanded/collapsed). This demo shows the inline rail — the toggle
* animates the rail's width via data-state. (The overlay/modal off-canvas mode the
* component also supports is described in the text, not staged here; see the Drawer
* demo for the same off-canvas pattern.)
*/
.sidebar-demo {
overflow: hidden;
border: 1px solid var(--border-strong);
border-radius: 0.5rem;
background: var(--surface-card);
}
.sidebar-demo__bar {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.6rem 0.9rem;
border-bottom: 1px solid var(--border-default);
background: var(--surface-subtle);
}
.sidebar-demo__toggle {
padding: 0.35rem 0.7rem;
font: inherit;
cursor: pointer;
border: 1px solid var(--border-interactive);
border-radius: 0.375rem;
background: var(--surface-card);
}
.sidebar-demo__brand {
font-weight: 600;
color: var(--color-text);
}
.sidebar-demo__body {
display: flex;
min-height: 12rem;
}
/* Panel: a rail whose width follows data-state. */
.sidebar-demo__panel {
display: flex;
flex-direction: column;
gap: 0.25rem;
width: 12rem;
padding: 0.75rem;
border-right: 1px solid var(--border-default);
background: var(--surface-card);
overflow: hidden;
transition: width 0.2s ease, padding 0.2s ease;
}
.sidebar-demo__panel[data-state="collapsed"] {
width: 0;
padding-inline: 0;
border-right-color: transparent;
}
/* Fully collapsed: hide the links so they leave the tab order too (a width:0 +
overflow:hidden rail would still keep them keyboard-focusable but invisible). */
.sidebar-demo__panel[data-state="collapsed"] .sidebar-demo__link {
display: none;
}
.sidebar-demo__link {
white-space: nowrap;
padding: 0.4rem 0.5rem;
border-radius: 0.375rem;
color: var(--color-text);
text-decoration: none;
}
.sidebar-demo__link:hover {
background: var(--surface-subtle);
}
.sidebar-demo__link:focus-visible {
outline: 2px solid var(--color-primary-hover);
outline-offset: 2px;
}
.sidebar-demo__content {
flex: 1;
padding: 1rem;
color: var(--color-text-muted);
}
@media (prefers-reduced-motion: reduce) {
.sidebar-demo__panel {
transition: none;
}
}
このデモに固有の消費側 JS はありません(挙動はコントローラが担います)。
これらのスタイルは共通のデザイントークン(ライト/ダーク両対応)を使います。 共通スタイルも一緒にコピーし、ルート要素の data-theme を切り替えればダークになります。
このコンポーネントを動かすために HTML へ記述する data-* 属性です。ルート要素に下の data-controller を付け、その内側に各 target / value / action を配置します。
ルート要素に付与
data-controller="stimeo--sidebar"
ターゲット
| 名前 | 説明 | 属性 |
|---|---|---|
trigger
|
パネルを切り替えるボタン。aria-expandedが展開状態を示す。 |
data-stimeo--sidebar-target="trigger" |
panel
|
サイドバーパネル。data-mode(inline/overlay)とdata-stateで状態を表す。 |
data-stimeo--sidebar-target="panel" |
backdrop
|
オーバーレイ時の背景。通常クリックでcloseに接続する。 | data-stimeo--sidebar-target="backdrop" |
値(Values)
| 名前 | 説明 | 属性 |
|---|---|---|
breakpoint
|
この幅(px)以上で inline、未満で overlay になる境界(既定768)。 |
data-stimeo--sidebar-breakpoint-value |
key
|
折りたたみ設定を永続化するlocalStorageキー。空で永続化を無効化(既定は空)。 |
data-stimeo--sidebar-key-value |
collapsed
|
宣言的な初期折りたたみ状態。永続値やDOM状態が無い場合に使用(既定 false)。 |
data-stimeo--sidebar-collapsed-value |
アクション
| 名前 | 説明 | アクション |
|---|---|---|
close
|
パネルを隠す(inlineは折りたたみ、overlayは閉じる)。 | stimeo--sidebar#close |
open
|
パネルを表示する(inlineは展開、overlayは開く)。 | stimeo--sidebar#open |
toggle
|
パネルを切り替える(inlineは折りたたみ/展開、overlayは開閉)。 | stimeo--sidebar#toggle |
状態フック
ライブラリが操作するのはこれらの ARIA / data 属性、カスタムプロパティだけです。見た目は利用側 CSS がこれらに反応して作ります([aria-selected] / [aria-expanded] / var(--stimeo--…) などのセレクタでフックします)。
| フック | 対象 | 意味 |
|---|---|---|
aria-expanded |
トリガー | パネルが展開(inline)/開(overlay)かどうか。 |
data-mode |
パネル | inline(breakpoint 以上)/ overlay(未満)。 |
data-state |
パネル | expanded / collapsed(inline)または open / closed(overlay)。 |
inert |
背景の兄弟要素 | オーバーレイが開いている間、パネル外へ付与。 |
hidden |
バックドロップ | オーバーレイが開いている間だけ外れる。 |