スクロール領域
stimeo--scroll-area
ネイティブなスクロール領域にキーボード到達性とスクロール状態フックを足す。
stimeo--scroll-area コントローラは、カスタムスクロールバーを描かずにネイティブなスクロール領域へアクセシビリティと CSS 状態を付与する。内容が溢れ、かつ viewport が自前のフォーカス可能要素を持たないとき、viewport をキーボードでスクロール可能にする(tabindex="0"、すでにアクセシブル名があれば role="region" も付与)。スクロール位置は data-scroll(start / middle / end)、溢れの有無は data-overflow、進捗は --stimeo-scroll-progress(0〜1)として公開し、利用側 CSS がスクロールシャドウを描ける。端到達時に stimeo--scroll-area:reach を発火し、scroll リスナと ResizeObserver は disconnect(Turbo 遷移含む)で破棄する。
キーボード操作
| キー | 動作 |
|---|---|
| ↑ / ↓ / ← / → | 領域をスクロール(フォーカス可能になればブラウザ既定)。 |
| PageUp / PageDown | 1 画面分スクロール。 |
| Home / End | 先頭 / 末尾へスクロール。 |
<%# Markup for the scroll-area demo.
The consumer (this markup) puts aria-label on the viewport. On overflow the library
adds tabindex to the viewport and (only when it has an accessible name) role="region",
and exposes data-scroll (start/middle/end) and --stimeo-scroll-progress.
Drawing the scroll shadow is demo.css's job, reading data-scroll. %>
<div class="scroll-area" data-controller="stimeo--scroll-area"
data-stimeo--scroll-area-orientation-value="vertical">
<div class="scroll-area__viewport"
data-stimeo--scroll-area-target="viewport"
aria-label="<%= t("components.scroll_area.demo.label") %>">
<p><%= t("components.scroll_area.demo.intro") %></p>
<% 12.times do |i| %>
<p class="scroll-area__line"><%= t("components.scroll_area.demo.line", number: i + 1) %></p>
<% end %>
</div>
</div>
/* Presentation CSS for scroll-area. The library handles overflow detection, keyboard
reachability, and exposing data-scroll, so visuals like the scroll shadow are drawn
here by reading data-scroll. */
.scroll-area {
position: relative;
max-width: 420px;
border: 1px solid var(--border-strong);
border-radius: 8px;
}
/* The viewport is the element that actually scrolls; the library adds tabindex/role on overflow. */
.scroll-area__viewport {
max-height: 180px;
overflow-y: auto;
padding: 1rem;
}
/* Visible keyboard focus (tabindex=0 is added on overflow). */
.scroll-area__viewport:focus-visible {
outline: 2px solid var(--color-primary-hover);
outline-offset: -2px;
}
.scroll-area__viewport p {
margin: 0 0 0.75rem;
color: var(--color-text);
}
.scroll-area__line {
padding: 0.25rem 0;
border-bottom: 1px dashed var(--border-default);
}
/* Using data-scroll as the hook, show the scroll shadow only at the top/bottom edges. */
.scroll-area::before,
.scroll-area::after {
content: "";
position: absolute;
left: 0;
right: 0;
height: 24px;
pointer-events: none;
opacity: 0;
transition: opacity 0.15s ease;
}
.scroll-area::before {
top: 0;
background: linear-gradient(to bottom, rgba(15, 23, 42, 0.12), transparent);
}
.scroll-area::after {
bottom: 0;
background: linear-gradient(to top, rgba(15, 23, 42, 0.12), transparent);
}
/* If scrolled below the top (middle/end) show the top shadow; if above the bottom
show the bottom shadow. */
.scroll-area[data-scroll="middle"]::before,
.scroll-area[data-scroll="end"]::before {
opacity: 1;
}
.scroll-area[data-scroll="start"]::after,
.scroll-area[data-scroll="middle"]::after {
opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
.scroll-area::before,
.scroll-area::after {
transition: none;
}
}
このデモに固有の消費側 JS はありません(挙動はコントローラが担います)。
これらのスタイルは共通のデザイントークン(ライト/ダーク両対応)を使います。 共通スタイルも一緒にコピーし、ルート要素の data-theme を切り替えればダークになります。
このコンポーネントを動かすために HTML へ記述する data-* 属性です。ルート要素に下の data-controller を付け、その内側に各 target / value / action を配置します。
ルート要素に付与
data-controller="stimeo--scroll-area"
ターゲット
| 名前 | 説明 | 属性 |
|---|---|---|
viewport
必須
|
オーバーフローとスクロール位置を追跡するスクロール領域。 | data-stimeo--scroll-area-target="viewport" |
値(Values)
| 名前 | 説明 | 属性 |
|---|---|---|
orientation
|
追跡するスクロール軸(vertical/horizontal/both、既定vertical)。 |
data-stimeo--scroll-area-orientation-value |
イベント
| 名前 | 説明 | イベント |
|---|---|---|
reach
|
スクロールが端に到達すると一度だけ発火する。detailにedge(start/end)を含む。 | stimeo--scroll-area:reach |
状態フック
ライブラリが操作するのはこれらの ARIA / data 属性、カスタムプロパティだけです。見た目は利用側 CSS がこれらに反応して作ります([aria-selected] / [aria-expanded] / var(--stimeo--…) などのセレクタでフックします)。
| フック | 対象 | 意味 |
|---|---|---|
data-scroll |
ルート要素 | "start" / "middle" / "end" のスクロール位置。 |
data-overflow |
ルート要素 | スクロール可能なとき "true"。 |
--stimeo-scroll-progress |
ルート要素 | 0〜1 のスクロール進捗。 |