Twitter/Xのような文字数制限付き投稿フォームや、SEO対策のメタ説明文入力など、リアルタイムで文字数をカウントしてフィードバックを与えるUIは多くの場面で必要です。この記事では基本的なカウントから残り文字数・上限警告・バイト数カウント・絵文字対応まで解説します。
この記事でわかること
- 入力中にリアルタイムで文字数を表示する
- 「残り○文字」の表示と上限に近づいた際の色変更
- 上限超過時にそれ以上入力できないようにする
- バイト数(全角2バイト・半角1バイト)でカウントする
- 絵文字(サロゲートペア)を正確にカウントする
基本: リアルタイム文字数カウント
<textarea id="my-textarea" maxlength="200" placeholder="テキストを入力..."></textarea> <p><span id="char-count">0</span> / 200 文字</p>
$(function () {
$('#my-textarea').on('input', function () {
var count = $(this).val().length;
$('#char-count').text(count);
});
});
keyupではなくinputを使う
input イベントはペースト・IME変換・音声入力など全ての入力方法に対応します。keyup はキー操作のみで、スマホのIMEや一部のペーストが検出されない場合があります。残り文字数の表示と上限警告
<textarea id="tweet-area" placeholder="入力してください..."></textarea> <p>残り <span id="remain-count">140</span> 文字</p>
#remain-count.is-warning { color: #f59e0b; font-weight: bold; }
#remain-count.is-danger { color: #ef4444; font-weight: bold; }
$(function () {
var MAX = 140;
$('#tweet-area').on('input', function () {
var count = $(this).val().length;
var remain = MAX - count;
var $remain = $('#remain-count');
$remain.text(remain);
// 残り文字数に応じてクラスを付与
$remain
.toggleClass('is-warning', remain <= 20 && remain > 0)
.toggleClass('is-danger', remain <= 0);
// 上限を超えた場合は送信ボタンを無効化
$('#submit-btn').prop('disabled', remain < 0);
});
});
上限文字数を超えて入力できないようにする
maxlength 属性はシンプルですが、貼り付け(ペースト)でも制限されます。JavaScriptで細かく制御する場合は以下のようにします。
$(function () {
var MAX = 100;
$('#my-textarea').on('input', function () {
var val = $(this).val();
// 上限を超えたらトリミング(ペースト対策)
if (val.length > MAX) {
$(this).val(val.slice(0, MAX));
}
$('#char-count').text(Math.min(val.length, MAX));
});
});
maxlength属性との使い分け
HTML の
HTML の
maxlength 属性はブラウザが標準でサポートしている上限制限で信頼性が高いです。JavaScript での制御は、上限超過時に視覚的なフィードバックを提供したい場合や、全角・半角で異なるバイト数制限をかける場合に使います。バイト数カウント(全角2バイト・半角1バイト)
データベースのVARCHARや外部APIの制限がバイト数で指定されている場合のカウント方法です。
// 全角2バイト・半角1バイトとして計算
function byteLength(str) {
var count = 0;
for (var i = 0; i < str.length; i++) {
var code = str.charCodeAt(i);
count += (code > 255) ? 2 : 1; // 全角: 2バイト, 半角: 1バイト
}
return count;
}
$(function () {
$('#my-input').on('input', function () {
var bytes = byteLength($(this).val());
$('#byte-count').text(bytes);
});
});
絵文字(サロゲートペア)を正確にカウントする
JavaScriptの String.length は絵文字(?など)を2文字としてカウントします。Spread演算子 または [...str].length で正確にカウントできます。
// 絵文字を1文字としてカウント
function countChars(str) {
return [...str].length; // Spread演算子でサロゲートペアを1文字として扱う
}
$(function () {
$('#my-textarea').on('input', function () {
var val = $(this).val();
var count = countChars(val);
$('#char-count').text(count);
});
});
// 比較
var str = '?hello';
console.log(str.length); // 7(?が2文字と数えられる)
console.log([...str].length); // 6(?が1文字として数えられる)
Twitterはどう数えるか
Twitter/Xは絵文字を1文字としてカウントします(Unicode正規化後)。SNS系の文字数制限を実装する場合は
Twitter/Xは絵文字を1文字としてカウントします(Unicode正規化後)。SNS系の文字数制限を実装する場合は
[...str].length を使うのが適切です。カウント方法の比較
| 方法 | 「あ」 | 「a」 | 「?」 | 用途 |
|---|---|---|---|---|
str.length |
1 | 1 | 2 | 最も一般的な文字数 |
[...str].length |
1 | 1 | 1 | 絵文字対応の文字数(Twitter等) |
| byteLength(全角2) | 2 | 1 | 4 | DBバイト数制限 |
maxlength属性 |
1 | 1 | 2 | ブラウザ標準(str.lengthと同じ) |
まとめ
jQueryで文字数カウントを実装する際のポイントをまとめます。
- 基本:
inputイベント +val().length - 残り文字数:
MAX - countで計算し、0以下で警告スタイル - 上限制限:
maxlength属性 + ペースト対策でslice(0, MAX) - バイト数: 全角2・半角1で独自関数を用意
- 絵文字対応:
[...str].lengthでサロゲートペアを1文字として扱う
関連記事: フォームバリデーション完全ガイド / 文字数が一定以上の場合に省略する方法
よくある質問(FAQ)
Q改行もカウントに含まれますか?
A
val().length は改行文字(\n)も1文字としてカウントします。改行を除いたカウントが必要な場合は val().replace(/\n/g, "").length を使ってください。Windowsの改行(\r\n)を除く場合は replace(/\r?\n/g, "") を使います。Q文字数超過時に送信ボタンをグレーアウトしたいです。
A
$("#submit-btn").prop("disabled", count > MAX) でボタンを disabled 状態にできます。CSSで button:disabled { opacity: 0.5; cursor: not-allowed; }を追加するとグレーアウト表示になります。Q複数のテキストエリアに同時に適用したいです。
A
textarea[data-max] のように data属性で上限を各要素に設定し、$("textarea[data-max]").each() または委譲イベントで一括管理できます。各テキストエリアの隣に .char-counter などのspan要素を置き、$(this).next(".char-counter").text(count) で更新します。Qページ読み込み時に既に値が入っている場合はどうすれば?
Aページ読み込み完了時にも一度カウント処理を実行してください。
$(function() { $("#my-textarea").trigger("input"); }) で input イベントを手動発火させると、初期値を反映したカウントが表示されます。Q文字数に応じてプログレスバーを表示したいです。
Aカウントを MAX で割った割合(
count / MAX * 100)を計算し、$('#progress').css("width", percent + "%") でプログレスバーの幅を更新してください。CSSのトランジションを付けるとスムーズに伸縮します。
