【jQuery/JS】文字数をカウントする完全ガイド|リアルタイム・残り文字数・上限警告・バイト数・絵文字対応まで

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 の 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系の文字数制限を実装する場合は [...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改行もカウントに含まれますか?
Aval().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複数のテキストエリアに同時に適用したいです。
Atextarea[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のトランジションを付けるとスムーズに伸縮します。