レーティング
stimeo--rating
順序尺度の星評価。aria-checked・ロービング tabindex・クランプ矢印・プレビュー・クリアを担う。
stimeo--rating コントローラは、APG の Radio Group パターンを順序尺度として実装します(aria-checked は常に 1 つ)。汎用ラジオと異なり意図的にループせず、矢印は上限/下限で止まります。clearable のときは選択中のシンボルをクリックすると 0 に解除でき、ホバー/フォーカスは data-rating-hover で塗り範囲をプレビューします。 readonly モードでは非対話な role="img" として表示します。値は hidden field に反映され、change ごとに stimeo--rating:change を発火します。星の見た目はこの Playground 側が持ちます。
キーボード操作
| キー | 動作 |
|---|---|
| → / ↑ | 評価を 1 上げる(上限で止まる)。 |
| ← / ↓ | 評価を 1 下げる(clearable なら 0 まで)。 |
| Home / End | 最小 / 最大へジャンプ。 |
| Space / Enter | フォーカス中のシンボルを選択。 |
<%# Markup for the rating (APG Radio Group, ordinal scale) demo.
Each symbol is role="radio" with an aria-label ("3 stars", etc.). Selection is
aria-checked; the currently filled range is data-rating-hover (the selected value or
a hover/focus preview). The star look is the consumer's CSS. %>
<div class="rating-demo" role="radiogroup" aria-label="<%= t('components.rating.demo.label') %>"
data-controller="stimeo--rating"
data-stimeo--rating-value-value="0" data-stimeo--rating-max-value="5">
<% (1..5).each do |n| %>
<span class="rating-demo__star" role="radio" aria-checked="false"
aria-label="<%= t('components.rating.demo.star', count: n) %>"
tabindex="<%= n == 1 ? 0 : -1 %>"
data-rating-value="<%= n %>" data-stimeo--rating-target="symbol"
data-action="click->stimeo--rating#select
mouseenter->stimeo--rating#preview
mouseleave->stimeo--rating#endPreview
focus->stimeo--rating#preview
blur->stimeo--rating#endPreview
keydown->stimeo--rating#onKeydown">
<svg class="rating-demo__icon" viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 2l2.9 6.26 6.86.6-5.2 4.52 1.56 6.72L12 17.1 5.88 20.6l1.56-6.72-5.2-4.52
6.86-.6z"></path>
</svg>
</span>
<% end %>
<input type="hidden" name="rating" value="0" data-stimeo--rating-target="field" />
<%# Subscribe to the change event to show the current value (updated by demo.js). %>
<span class="rating-demo__status" aria-live="polite"
data-empty-text="<%= t('components.rating.demo.empty') %>"
data-rated-template="<%= t('components.rating.demo.rated') %>"><%= t(
'components.rating.demo.empty'
) %></span>
</div>
/*
* Presentation-only styles for the rating demo.
* The currently filled range is expressed via [data-rating-hover] (the selected value
* or a hover/focus preview).
*/
.rating-demo {
display: inline-flex;
align-items: center;
gap: 0.25rem;
}
.rating-demo__star {
display: inline-flex;
padding: 0.125rem;
border-radius: 0.25rem;
cursor: pointer;
line-height: 0;
}
.rating-demo__star:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.rating-demo__icon {
width: 1.75rem;
height: 1.75rem;
fill: var(--slate-300);
transition: fill 0.12s ease;
}
/* Symbols within the filled range are colored with the accent (amber). */
.rating-demo__star[data-rating-hover] .rating-demo__icon {
fill: var(--amber-500);
}
.rating-demo__status {
margin-left: 0.5rem;
font-size: 0.85rem;
color: var(--color-text-muted);
}
// Demo script that subscribes to the rating change event and shows the current value.
// The copy uses the localized template in a data attribute (substituting "{n}" with
// the value) and an empty-state text.
document.addEventListener('stimeo--rating:change', function (event) {
const status = document.querySelector('.rating-demo__status');
if (!status) return;
const value = event.detail.value;
if (value === 0) {
status.textContent = status.dataset.emptyText || '';
} else {
status.textContent = (status.dataset.ratedTemplate || '').replace('{n}', String(value));
}
});
これらのスタイルは共通のデザイントークン(ライト/ダーク両対応)を使います。 共通スタイルも一緒にコピーし、ルート要素の data-theme を切り替えればダークになります。
このコンポーネントを動かすために HTML へ記述する data-* 属性です。ルート要素に下の data-controller を付け、その内側に各 target / value / action を配置します。
ルート要素に付与
data-controller="stimeo--rating"
ターゲット
| 名前 | 説明 | 属性 |
|---|---|---|
symbol
必須
|
順序尺度上の評価シンボル(role=radio)。1つが aria-checked。 |
data-stimeo--rating-target="symbol" |
field
|
現在の数値を反映する任意の隠しフィールド。 | data-stimeo--rating-target="field" |
値(Values)
| 名前 | 説明 | 属性 |
|---|---|---|
value
|
現在の評価値(既定0)。 | data-stimeo--rating-value-value |
max
|
最大評価値・シンボル数(既定5)。 | data-stimeo--rating-max-value |
clearable
|
true(既定)なら選択中シンボル再クリックで0に戻り、最小値も0になる。 | data-stimeo--rating-clearable-value |
readonly
|
true で非操作の role=img 表示にする(既定 false)。 |
data-stimeo--rating-readonly-value |
アクション
| 名前 | 説明 | アクション |
|---|---|---|
endPreview
|
塗りつぶし範囲を選択値に戻す(mouseleave/blur 時)。 | stimeo--rating#endPreview |
onKeydown
|
矢印・Home/End・Space/Enter のキー操作。ラップせずクランプ。 | stimeo--rating#onKeydown |
preview
|
ホバー・フォーカス時に data-rating-hover で塗りをプレビューする。 |
stimeo--rating#preview |
select
|
クリックしたシンボルを選択。clearable かつ選択済みなら0に戻す。 | stimeo--rating#select |
イベント
| 名前 | 説明 | イベント |
|---|---|---|
change
|
値が変わるたびに発火。detail に新しい値を載せる。 | stimeo--rating:change |
状態フック
ライブラリが操作するのはこれらの ARIA / data 属性、カスタムプロパティだけです。見た目は利用側 CSS がこれらに反応して作ります([aria-selected] / [aria-expanded] / var(--stimeo--…) などのセレクタでフックします)。
| フック | 対象 | 意味 |
|---|---|---|
aria-checked |
シンボル | 選択値のシンボルのみ "true"。 |
data-rating-hover |
シンボル | 表示中の塗り範囲(選択値またはプレビュー)に入るシンボルへ付与。 |
tabindex |
シンボル | 選択中(または先頭)が 0、他は -1(ロービング)。 |