Webパーツ辞典

残り文字数つき入力欄Character count

複数行の入力欄の下に「あと 9 文字」のように残りの文字数が出る部品。上限を超えると「11 文字多すぎます」に変わり、枠が赤く太くなる。

表示例

80文字以内で入力してください

別名・英語表記

  • 文字数カウンター付き入力欄
  • 文字数制限つき入力欄
  • 残り文字数表示
  • あと何文字
  • 文字数上限つきテキストエリア
  • Character count

実装例

<div class="x-character-count">
  <label class="x-character-count__l" for="x-character-count-i">自己紹介</label>
  <p class="x-character-count__h" id="x-character-count-h">80文字以内で入力してください</p>
  <!-- maxlength で打てなくするのではなく、超えても入力させて「何文字多いか」を伝える -->
  <textarea class="x-character-count__i" id="x-character-count-i" name="bio" rows="4"
            aria-describedby="x-character-count-h">週末は子どもと近所の公園を歩いています。仕事ではWebサイトの制作を担当し、最近はフォームの使いやすさを見直しています。よろしくお願いします。</textarea>
  <!-- 目で見る残り文字数。1文字ごとに読み上げると入力の邪魔になるので、読み上げからは外す -->
  <p class="x-character-count__n" aria-hidden="true">あと <b class="x-character-count__v">9</b> 文字</p>
  <!-- 読み上げ用。入力が止まって約1秒たってから JS で「あと9文字入力できます」を書き込む。
       超えたら「11文字多すぎます」と書き、根元に data-over を付けて文言・アイコンで示す -->
  <span class="x-character-count__sr" aria-live="polite"></span>
</div>

AIへの指示文

「残り文字数つき入力欄(Character count)」を実装してください。

## これは何か
複数行の入力欄の下に「あと 9 文字」のように残りの文字数が出る部品。上限を超えると「11 文字多すぎます」に変わり、枠が赤く太くなる。

## 使いどころ
- 自己紹介・問い合わせ・レビューのように、文字数に上限がある自由記述
- SNS の投稿や広告文のように、決まった長さに収める必要がある文章

## 実装の要件
- label + 補足文(上限)+ textarea[aria-describedby] + 見える残り文字数(aria-hidden)+ 読み上げ用の span[aria-live=polite](見た目は隠す)
- input イベントで数え直し、見える数字はすぐ更新する。読み上げ用の文言は setTimeout で約1秒待ち、次の入力が来たら取り消す(デバウンス)
- 超えたら根元に data-over のような印を付け、文言を「あと n 文字」から「n 文字多すぎます」へ替える。送信時は上限を超えていたらエラーにする(切り詰めない)
- JavaScript が動かない環境でも上限が分かるよう、補足文は HTML に最初から書いておく
- テキストエリアとの違い: 上限と残りの文字数を入力中に見せる。上限が無い、または上限に届くことがまず無いなら、普通のテキストエリアにして補足文で上限だけ書く
- maxlength で打てなくしない。GOV.UK Design System は上限を超えても入力させ、何文字多いかを伝える。貼り付けた文章が黙って切られると、どこが消えたか気づけない
- 上限がふだんの長さよりずっと大きいなら、残りが少なくなってから(GOV.UK Design System の例では上限の75%から)表示を出す
- JavaScript の length は UTF-16 の単位で数えるので、絵文字や一部の漢字は1文字が2と数えられる。見た目の1文字で数えるなら Intl.Segmenter を使い、サーバー側の数え方とそろえる
- 超えた状態を赤い色だけで示さない。「11 文字多すぎます」という文言と、太い枠でも示す

## アクセシビリティの要件
- 上限は入力前に分かるよう補足文(「80文字以内で入力してください」)に書き、aria-describedby で textarea に結ぶ(3.3.2 ラベル又は指示)
- 1文字ごとに残り文字数を読み上げない。見える数字は aria-hidden にし、読み上げ用の aria-live="polite" の領域には入力が止まってから(1秒前後)書き込む(4.1.3 ステータスメッセージ)
- 上限を超えたときは色だけでなく文言で示す(1.4.1 色の用途)。送信時にエラーとするなら aria-invalid="true" と、何文字多いかのメッセージを結ぶ
- エラー時の赤は背景に対して文字で 4.5:1 以上にする

## 参考にする実装
この形を出発点にして、プロジェクトの命名規則・色・余白に合わせて調整してください。

```html
<div class="x-character-count">
  <label class="x-character-count__l" for="x-character-count-i">自己紹介</label>
  <p class="x-character-count__h" id="x-character-count-h">80文字以内で入力してください</p>
  <!-- maxlength で打てなくするのではなく、超えても入力させて「何文字多いか」を伝える -->
  <textarea class="x-character-count__i" id="x-character-count-i" name="bio" rows="4"
            aria-describedby="x-character-count-h">週末は子どもと近所の公園を歩いています。仕事ではWebサイトの制作を担当し、最近はフォームの使いやすさを見直しています。よろしくお願いします。</textarea>
  <!-- 目で見る残り文字数。1文字ごとに読み上げると入力の邪魔になるので、読み上げからは外す -->
  <p class="x-character-count__n" aria-hidden="true">あと <b class="x-character-count__v">9</b> 文字</p>
  <!-- 読み上げ用。入力が止まって約1秒たってから JS で「あと9文字入力できます」を書き込む。
       超えたら「11文字多すぎます」と書き、根元に data-over を付けて文言・アイコンで示す -->
  <span class="x-character-count__sr" aria-live="polite"></span>
</div>
```

```css
/* 貼った先のリセットに頼らないよう、この部品の中だけ border-box にする */
.x-character-count,
.x-character-count *:not([class*="fa-"]),
.x-character-count *:not([class*="fa-"])::before,
.x-character-count *:not([class*="fa-"])::after {
  box-sizing: border-box;
  /* 貼った先の既定の書体に引きずられないようにする。書体が変わると
     文字の幅と高さが変わり、枠のサイズまでずれる */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Sans", "Noto Sans JP", "Yu Gothic UI", Meiryo, sans-serif;
}

.x-character-count {
  width: 300px;
  max-width: 100%;
  color: #1b2028;
}
.x-character-count__l {
  display: block;
  font-size: 12px;
  font-weight: 700;
}
.x-character-count__h {
  margin: 2px 0 6px;
  color: #5b6472;
  font-size: 11px;
}
.x-character-count__i {
  display: block;
  width: 100%;
  padding: 8px 10px;
  border: 1px solid #7f8a99;
  border-radius: 8px;
  background: #fff;
  color: #1b2028;
  font: inherit;
  font-size: 13px;
  line-height: 1.6;
  resize: vertical;
}
.x-character-count__i:focus-visible {
  outline: 2px solid #1d4ed8;
  outline-offset: 1px;
}
.x-character-count__n {
  margin: 6px 0 0;
  color: #5b6472;
  font-size: 12px;
}
.x-character-count__v {
  color: #1b2028;
  font-variant-numeric: tabular-nums;
}
/* 超えたとき。赤だけに頼らず、文言(「11文字多すぎます」)と太字、アイコンを JS で入れて示す */
.x-character-count[data-over] .x-character-count__i {
  border: 2px solid #b91c1c;
}
.x-character-count[data-over] .x-character-count__n,
.x-character-count[data-over] .x-character-count__v {
  color: #b91c1c;
  font-weight: 700;
}
.x-character-count__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
```

## 出力の約束
- HTML と CSS を分けて出す。JavaScript が要るときは素の JavaScript で書き、UIフレームワークは使わない。
- 参考実装がアイコンに Font Awesome のクラスを使っている場合は、プロジェクトで使っているアイコンかインライン SVG に置き換えてよい。
- 上のアクセシビリティ要件を満たす。満たせない箇所があるときは、理由を添えて先に知らせる。
- 色・角丸・余白は既存のデザイントークンがあればそれを使う。無ければ CSS 変数として切り出す。

使いどころ

  • 自己紹介・問い合わせ・レビューのように、文字数に上限がある自由記述
  • SNS の投稿や広告文のように、決まった長さに収める必要がある文章

注意点

  • テキストエリアとの違い: 上限と残りの文字数を入力中に見せる。上限が無い、または上限に届くことがまず無いなら、普通のテキストエリアにして補足文で上限だけ書く
  • maxlength で打てなくしない。GOV.UK Design System は上限を超えても入力させ、何文字多いかを伝える。貼り付けた文章が黙って切られると、どこが消えたか気づけない
  • 上限がふだんの長さよりずっと大きいなら、残りが少なくなってから(GOV.UK Design System の例では上限の75%から)表示を出す
  • JavaScript の length は UTF-16 の単位で数えるので、絵文字や一部の漢字は1文字が2と数えられる。見た目の1文字で数えるなら Intl.Segmenter を使い、サーバー側の数え方とそろえる
  • 超えた状態を赤い色だけで示さない。「11 文字多すぎます」という文言と、太い枠でも示す

アクセシビリティの要点

  • 上限は入力前に分かるよう補足文(「80文字以内で入力してください」)に書き、aria-describedby で textarea に結ぶ(3.3.2 ラベル又は指示)
  • 1文字ごとに残り文字数を読み上げない。見える数字は aria-hidden にし、読み上げ用の aria-live="polite" の領域には入力が止まってから(1秒前後)書き込む(4.1.3 ステータスメッセージ)
  • 上限を超えたときは色だけでなく文言で示す(1.4.1 色の用途)。送信時にエラーとするなら aria-invalid="true" と、何文字多いかのメッセージを結ぶ
  • エラー時の赤は背景に対して文字で 4.5:1 以上にする

作るときに使えるツール

関連するパーツ