Tout d'abord, il faut faire la vue du formulaire avec le compteur qui sera calculé en javascript.

<div id="counter"><span>0</span>/1700 caractères autorisés.</div>

<form action="/" method="post">
  <p>
    <textarea rows="6" cols="50" name="firstField" class="counter-field" ></textarea>
  </p>
  <p>
    <textarea rows="6" cols="50" name="secondField" class="counter-field" ></textarea>
  </p>
  <p>
  <textarea rows="6" cols="50" name="thirdField" class="counter-field" ></textarea>
  </p>
  <p>
    <textarea rows="6" cols="50" name="fourthField" class="counter-field" ></textarea>
  </p>
</form>

<script type="text/javascript">
  var maxCharsAllowed = 1700;
</script>

La variable globale "maxCharsAllowed" permet de définir le nombre maximum de caractères requis, il peut être écrit dynamiquement via un fichier de conf. récupéré avec un script PHP par exemple.

Ensuite on écrit le script JS qui va calculer en "temps réèl" le nombre de caractères saisis dans les champs concernés.

$(document).ready(function(){
  updateCounter(maxCharsAllowed);

  // On écoute le relachement d'une touche dans les champs du compteur.
  $('.counter-field').keyup(function(){
    $(this).change();
  });

  // On écoute le changement dans les champs du compteur.
  $('.counter-field').change(function(){
    updateCounter(maxCharsAllowed);
  });
});

/**
 * Met à jour le compteur js.
 *
 * @return void
*/
function updateCounter(maxCharsAllowed)
{
  var counter = 0;

  // On calcule le nb de caractères sur tous les champs définis avec cette classe.
  $('.counter-field').each(function(){
    counter += $(this).val().length;
  });

  // On remplace la valeur du compteur.
  $('#counter span').html(counter);

  // Si le nb de caractères a dépassé le maxi autorisé, on ajoute la classe css.
  if (counter > maxCharsAllowed) {
    $('#counter span').addClass('warning');
  } else {
    $('#counter span').removeClass('warning');
  }
}

L'astuce consiste à mettre 2 écouteurs sur les champs qui doivent être comptés.

L'écouteur sur l'évènement "keyup" permet juste de diffuser l'évènement "change" à chaque fois qu'une touche du clavier est relachée.

En effet, l'évènement "change" étant diffusé que lorsque le focus sort du champ, cette astuce permet de modifier en temps réel le compteur de caractères.

Vous me direz mais alors pourquoi ne pas faire la mise à jour lors de l'évènement "keyup" ?

Tout simplement parce que si l'utilisateur effectue un "copier/coller" avec la souris l'évènement "keyup" ne sera pas diffusé.

Interdire le "copier/coller" n'est pas envisageable car c'est le cas d'utilisation le plus fréquent.

Cependant, dans ce cas la mise à jour du compteur ne se fait pas si l'utilisateur ne change pas de champ, même en forçant la mise à jour sur les 2 évènements "cut" et "paste" car ils sont diffusés avant l'écriture ou la suppression des valeurs du champ.

La seule solution que j'ai trouvé est de mettre un timeout sur les évènements "cut" et "paste" car seul avec IE il est possible de récupérer le contenu du "clipboard". Ce qui est potentiellement une faille de sécurité.

$('.counter-field').bind('cut paste', function(e){
  var el = $(this);
  setTimeout(function() {
    $(el).change();
  }, 100);
});

Et voilà, il ne reste plus qu'à faire la css et le tour est joué.

#counter {
  border: 1px dashed #DDD;
  margin: 5px 0;
  padding: 10px;
  text-align: center;
  width: 400px;
}

#counter span {
  color: green;
}

#counter span.warning {
  color: red;
}

On pourrait pousser plus loin le caractère générique de la fonction en ajoutant en paramètre l'identifiant du compteur et les classes des champs de texte à compter afin de mettre plusieurs compteurs sur la même page.

@+

NairuS