Stimeo UI は Rails 向けに 挙動だけ を提供する Stimulus コントローラ群です。
ARIA 状態、キーボード操作、フォーカス管理を data-* 属性で駆動し、CSS は一切同梱しません。見た目は完全にあなたのものです。
ステータス: alpha(0.x)です。
stimeo--*の属性 API は 1.0 までに変わる可能性があります。
Rails + importmap(推奨)
bundle add stimeo-ui
bin/rails generate stimeo:install
このコマンド(stimeo:install ジェネレータ)は、次のセットアップを自動で行います:
- ビルド済みのライブラリ本体を
vendor/javascript/stimeo/に配置(同梱)し、 config/importmap.rbにstimeo-uiの読み込み設定(importmap のエントリ)を追加し、- すべての
stimeo--*コントローラを Stimulus に登録します。
何度実行しても安全です。ライブラリ本体は最新版に置き換わり、importmap の設定や既存の記述はそのまま残ります。
あとは HTML に属性を書くだけでコンポーネントが動きます:
<div data-controller="stimeo--dropdown">
<button data-stimeo--dropdown-target="trigger"
data-action="click->stimeo--dropdown#toggle">Menu</button>
<div data-stimeo--dropdown-target="menu" hidden>…</div>
</div>
npm(jsbundling など任意のバンドラ)
npm install stimeo-ui @hotwired/stimulus
import { Application } from "@hotwired/stimulus";
import { registerStimeo } from "stimeo-ui";
const application = Application.start();
registerStimeo(application); // すべての stimeo--* コントローラを登録
必要なコントローラだけを使いたい場合は、stimeo-ui/controllers/* から個別に
import して、好きな識別子で登録することもできます:
import { Application } from "@hotwired/stimulus";
import { DialogController } from "stimeo-ui/controllers/dialog_controller";
const application = Application.start();
application.register("stimeo--dialog", DialogController);
オプトインの positioning(フローティング配置)
popover / tooltip / hover-card のような「何かに沿って浮かぶ UI」では、開いたり閉じたりといった動きはコントローラが担います。一方でどこに表示するか(位置)は、通常はあなたの CSS で決めます。画面の端に来たときに自動で向きを反転させて収める、といった「動的な位置合わせ」が欲しいときだけ、@floating-ui/dom を使う positioning モジュール(stimeo-ui/positioning)を任意で追加します。必要なければ追加は不要で、本体(コアの stimeo-ui)には positioning モジュールも @floating-ui/dom も含まれないため、追加の依存はゼロのままです。使う場合は config/importmap.rb に次の 2 行を足して、サブパスと依存ライブラリも読み込めるようにします:
pin "stimeo-ui/positioning", to: "stimeo/positioning/index.js"
pin "@floating-ui/dom", to: "floating-ui-dom.js"
Lint(リント)
Stimeo UI はヘッドレス(見た目を持たない)なので、role などの WAI-ARIA 属性は
あなた自身が書きます。一部のコントローラは、その属性を手がかりに要素を探します(例: data-grid は [role="row"] で行を見つけます)。そのため、あなたのマークアップには
<ul role="menu"> / <div role="radio"> / <td role="gridcell"> のような、APG に沿った正しいカスタムウィジェットの ARIA が含まれます。
ところが厳格な静的 a11y リンタ(Biome の recommended プリセット(2.5 以降)や
eslint-plugin-jsx-a11y)は、こうした正しい書き方をエラー扱いします。<button> のようなネイティブ要素を前提にしたチェックだからです。そこで Stimeo UI のマークアップを書く場所だけ 該当ルールを緩めます(includes のパスは自分の構成に合わせて調整します)。
Biome なら biome.json に次の overrides を追加します:
{
"overrides": [
{
"includes": ["app/components/**"],
"linter": {
"rules": {
"a11y": {
"noNoninteractiveElementToInteractiveRole": "off",
"noRedundantRoles": "off",
"useSemanticElements": "off",
"useFocusableInteractive": "off",
"noNoninteractiveTabindex": "off"
}
}
}
}
]
}
ESLint(eslint-plugin-jsx-a11y)を使う場合も、同じ考え方で、対象のパス(.eslintrc.json など)だけ同等のルールを off にします。
次のステップ
- コンポーネントカタログでライブデモを見る。
- デモが前提とする共通スタイルをコピーする。
- Inspector(
stimeo check)でマークアップを検査する。