文字数カウンタ
stimeo--character-counter
残りの文字数を出し、上限が近いことと超えたことを伝えます。読み上げは打ち終わってから。
入力欄の長さを見て、残りまたは使った文字数を表示します。上限が近いときと超えたときは、それぞれ CSS から読める形で伝わるので、色を変えるなどの見せ方は自由です。上限を超えた入力欄は、読み上げにも不正な状態として伝わります。表示はすぐ変わりますが、読み上げは打ち終わって少し経ってから届きます。打鍵のたびに読み上げが流れることはありません。読み上げの文言は言語ごとに用意できます。
実行中
キーボード操作
このコンポーネント自体はキーボード操作を持ちません。
<%# Markup for the character-counter demo. The visible output updates on every
keystroke, while the settled remaining count is debounced into the shared
stimeo--announcer your app seats once, in its layout (the settled count is the
transition worth reading; the visible output is not itself a live region). This
demo's CSS styles the root's near/over hooks and the over-limit aria-invalid;
watching the field needs no consumer JavaScript. %>
<% announcement = t("components.character_counter.demo.announcement") %>
<div class="character-counter-demo">
<label class="character-counter-demo__label" for="cc-message">
<%= t("components.character_counter.demo.label") %>
</label>
<div
class="character-counter"
data-controller="stimeo--character-counter"
data-stimeo--character-counter-max-value="140"
data-stimeo--character-counter-warn-at-value="20"
data-stimeo--character-counter-announce-text-value="<%= announcement %>">
<textarea
id="cc-message"
class="character-counter__input"
rows="3"
data-stimeo--character-counter-target="input"
aria-describedby="cc-message-count"
placeholder="<%= t('components.character_counter.demo.placeholder') %>"></textarea>
<span
id="cc-message-count"
class="character-counter__output"
data-stimeo--character-counter-target="output"></span>
</div>
</div>
/*
* Presentation-only styles for the character counter demo.
* The library updates the count text and toggles data-near-limit / data-over-limit on
* the root (and aria-invalid on the field); this CSS reacts to those hooks.
*/
.character-counter-demo {
display: flex;
flex-direction: column;
gap: 0.5rem;
max-width: 32rem;
}
.character-counter-demo__label {
font-weight: 600;
color: var(--fg);
}
.character-counter {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.character-counter__input {
width: 100%;
padding: 0.5rem;
border: 1px solid var(--border);
border-radius: 0.375rem;
font: inherit;
resize: vertical;
}
.character-counter__output {
align-self: flex-end;
font-size: 0.85rem;
font-variant-numeric: tabular-nums;
color: var(--color-text-muted);
}
/* Warn as the remaining count gets low, then signal the over-limit state. */
.character-counter[data-near-limit] .character-counter__output {
color: var(--accent-700);
}
.character-counter[data-over-limit] .character-counter__output {
color: var(--danger-500);
font-weight: 600;
}
.character-counter__input[aria-invalid="true"] {
border-color: var(--danger-500);
}
このデモに固有の消費側 JS はありません(挙動はコントローラが担います)。
これらのスタイルは共通のデザイントークン(ライト/ダーク両対応)を使います。共通スタイルも一緒にコピーし、ルート要素の data-theme を切り替えればダークになります。
このコンポーネントを動かすために HTML へ記述する data-* 属性です。ルート要素に下の data-controller を付け、その内側に各 target / value / action を配置します。
ルート要素に付与
data-controller="stimeo--character-counter"
ターゲット
| 名前 | 説明 | 属性 |
|---|---|---|
input
|
監視対象の入力欄。input/textarea に直接付けた場合はコントローラ要素自身を使う。 |
data-stimeo--character-counter-target="input" |
output
|
カウントを即時表示する任意要素。ライブリージョンにはしない。 | data-stimeo--character-counter-target="output" |
値(Values)
| 名前 | 説明 | 属性 |
|---|---|---|
max
|
有限な非負整数の上限。0 は上限なし(使用数のみ表示)。既定 0。 | data-stimeo--character-counter-max-value |
warnAt
|
有限な非負整数の警告しきい値。0 で無効。既定 0。 | data-stimeo--character-counter-warn-at-value |
mode
|
表示モード。remaining / used / both。不明値は remaining。 |
data-stimeo--character-counter-mode-value |
announceText
|
共有 announcer 用の任意テンプレート。{count} / {length} / {remaining} / {max} / {over} を使用可能。 |
data-stimeo--character-counter-announce-text-value |
イベント
| 名前 | 説明 | イベント |
|---|---|---|
change
|
確定した利用者入力で長さが変わったときだけ発火。detail.length / detail.remaining / detail.over を伴う。 |
stimeo--character-counter:change |
reconcile
|
実行時の target / Value 再調停で同じ導出 detail が変わったときだけ 1 回発火。表示だけの変更では発火しない。 | stimeo--character-counter:reconcile |
状態フック
ライブラリが操作するのはこれらの ARIA / data 属性、カスタムプロパティだけです。見た目は利用側 CSS がこれらに反応して作ります([aria-selected] / [aria-expanded] / var(--stimeo--…) などのセレクタでフックします)。
| フック | 対象 | 意味 |
|---|---|---|
data-over-limit |
ルート要素 | 値が max を超えると付与。 |
data-near-limit |
ルート要素 | 残数が warnAt 以下で、まだ超過していないときに付与。 |
aria-invalid |
入力欄 | max を超えている間 "true" を付与。 |
テキスト |
output 要素 | 現在のモードで即時更新される残り / 使用文字数。 |