Skip to content
← 1001 Widgets
N° 018 · ●○○

Social post counter

The characters of a post counted live, with the limits of X, Bluesky, Instagram and LinkedIn. The right exercise to discover that an emoji does not always count as one.

HTMLJS
What you'll learn
  • Count characters with Intl.Segmenter
  • Compare a text against several limits
  • Find hashtags with a regular expression
Why this language

Pourquoi un compteur de caractères ? Quand on gère des réseaux sociaux, on écrit un post pour plusieurs plateformes, et chacune a sa limite. Le compteur évite de couper une phrase au mauvais endroit.

Le piège est caché : pour JavaScript, l'émoji 🚀 fait deux caractères. Pour l'œil, il en fait un. Intl.Segmenter compte comme l'œil.

Pourquoi en JavaScript simple ? Un champ, un événement input, et une boucle sur un tableau de réseaux. Tout le reste est de l'affichage.

How it works
  1. LE HTML

    <textarea id="post" aria-label="Votre post"></textarea>
    <ul id="limites"></ul>
  2. LES RÉSEAUX

    Un tableau : ajouter une plateforme, c'est ajouter une ligne.

    const RESEAUX = [['X', 280], ['Bluesky', 300], ['Instagram', 2200], ['LinkedIn', 3000]];
  3. COMPTER COMME L'ŒIL

    length compte des unités de code. Segmenter compte des caractères visibles.

    const seg = new Intl.Segmenter('fr', { granularity: 'grapheme' });
    const compter = texte => [...seg.segment(texte)].length;
  4. AFFICHER

    function afficher() {
      const n = compter(document.getElementById('post').value);
      document.getElementById('limites').innerHTML = RESEAUX.map(([nom, limite]) => {
        const reste = limite - n;
        return `<li>${nom} : ${reste < 0 ? -reste + ' de trop' : reste + ' restants'}</li>`;
      }).join('');
    }
  5. LES HASHTAGS

    \p{L} accepte les lettres accentuées, le drapeau u est obligatoire.

    const hashtags = texte => texte.match(/#[\p{L}\d_]+/gu) || [];
    
    document.getElementById('post').addEventListener('input', afficher);
    afficher();
Pitfalls

PIÈGE 1 : Faire confiance à length

Pitfall

Mauvais : texte.length. « 🚀 » vaut 2, « 👨‍👩‍👧 » vaut 8. Le compteur ment dès qu'il y a un émoji.

Fix

Correct : Intl.Segmenter avec granularity: 'grapheme'.

PIÈGE 2 : Les liens sur X

Pitfall

Mauvais : compter un lien caractère par caractère. X compte tout lien comme 23 caractères, quelle que soit sa longueur.

Fix

Correct : remplacer chaque URL par 23 caractères avant de compter pour X.

PIÈGE 3 : Bloquer la saisie

Pitfall

Mauvais : un maxlength à 280. On ne peut plus coller un brouillon long pour le raccourcir ensuite.

Fix

Correct : laisser écrire, et montrer clairement le dépassement.

PERSONNALISER
  • Une jauge qui change de style au-delà de 90 % de la limite.
  • Un bouton « Copier pour Instagram » qui ajoute vos hashtags habituels à la fin.
  • Une alerte quand Instagram dépasse 30 hashtags, sa limite.
OPTIMISATION
  • Mettez en cache le Segmenter : le créer à chaque frappe coûte cher.
  • Pour un texte très long, ne recalculez qu'après une courte pause dans la frappe.
VERS REACT

Le texte va dans un useState, tout le reste se calcule pendant le rendu.

Le Segmenter se crée une seule fois, en dehors du composant.

Chaque réseau devient un petit composant Jauge qui reçoit n et la limite.

Variants
Comments
0/1000

Loading comments…

Audience measurement

With your consent, this site measures its traffic with Google Analytics and the Meta pixel, via Google Tag Manager. Nothing is loaded until you choose, and you can change your mind at any time with the "Cookies" link at the bottom of the page.