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

Step counter

A counter where you choose how much to add with each click: 1, 5, 10 or a custom step, with limits not to cross. The right exercise to move from one state to several states that depend on each other.

HTMLJS
What you'll learn
  • Keep several state values consistent
  • Clamp a value between a minimum and a maximum
  • Mark the active button with aria-pressed
Why this language

Pourquoi un compteur à pas réglable ? Le compteur de base ajoute toujours 1. Dès qu'on compte des points de vie, des calories ou des pompes, on veut avancer de 5 ou de 10 d'un coup.

Il y a maintenant deux états : la valeur et le pas. Et une règle : la valeur reste entre un minimum et un maximum, quel que soit le pas choisi. Les boutons se désactivent quand la borne est atteinte.

Pourquoi en JavaScript simple ? Deux variables, une fonction qui borne, une fonction qui affiche. C'est la suite logique du premier compteur.

How it works
  1. LE HTML

    Les pas sont des boutons à bascule : aria-pressed dit lequel est actif.

    <div id="pas">
      <button data-p="1" aria-pressed="true">1</button>
      <button data-p="5" aria-pressed="false">5</button>
      <button data-p="10" aria-pressed="false">10</button>
    </div>
    <button id="moins">−</button> <output id="val">0</output> <button id="plus">+</button>
  2. L'ÉTAT

    let valeur = 0, pas = 1;
    const MIN = -999, MAX = 999;
  3. BORNER

    Une seule fonction garde la valeur dans les limites, pour tous les boutons.

    const borne = v => Math.min(MAX, Math.max(MIN, v));
  4. CHOISIR UN PAS

    function choisir(p) {
      pas = p;
      document.querySelectorAll('#pas button').forEach(b =>
        b.setAttribute('aria-pressed', String(Number(b.dataset.p) === p)));
    }
  5. AFFICHER

    Les boutons se désactivent quand la borne est atteinte.

    function afficher() {
      document.getElementById('val').textContent = valeur;
      document.getElementById('plus').disabled = valeur >= MAX;
      document.getElementById('moins').disabled = valeur <= MIN;
    }
    
    document.getElementById('plus').addEventListener('click', () => { valeur = borne(valeur + pas); afficher(); });
    document.getElementById('moins').addEventListener('click', () => { valeur = borne(valeur - pas); afficher(); });
Pitfalls

PIÈGE 1 : Lire le pas comme du texte

Pitfall

Mauvais : pas = bouton.dataset.p. Avec 0 + '5', on obtient '05', puis '055'.

Fix

Correct : Number(bouton.dataset.p), ou parseInt pour un champ saisi.

PIÈGE 2 : Dépasser la borne

Pitfall

Mauvais : vérifier seulement valeur < MAX avant d'ajouter. À 998 avec un pas de 5, on arrive à 1003.

Fix

Correct : calculer la nouvelle valeur, puis la borner avec Math.min et Math.max.

PIÈGE 3 : Un pas libre sans contrôle

Pitfall

Mauvais : accepter tout ce qui est tapé. Un pas de 0, négatif ou de dix chiffres casse le compteur.

Fix

Correct : n'accepter qu'un entier entre 1 et une limite raisonnable, sinon garder le pas précédent.

PERSONNALISER
  • Un appui long sur + qui accélère, avec setInterval lancé au pointerdown et arrêté au pointerup.
  • Les flèches du clavier pour avancer, et Maj + flèche pour avancer de 10.
  • Des bornes réglables, pour compter à rebours à partir d'un nombre de vies.
OPTIMISATION
  • Rassemblez valeur, pas et bornes dans un seul objet d'état : une seule fonction afficher le lit en entier.
  • Mettez le pas dans l'URL avec URLSearchParams pour partager un réglage.
VERS REACT

La valeur et le pas sont deux useState distincts.

Les boutons désactivés se calculent pendant le rendu, à partir de la valeur.

La fonction borne vit en dehors du composant : elle ne dépend d'aucun état.

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.