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

Countdown

A countdown to New Year, or to the date of your choice. The right exercise to learn how to handle dates without getting lost in time zones.

HTMLJS
What you'll learn
  • Subtract two dates with the Date object
  • Split milliseconds into days, hours, minutes
  • Read the value of a datetime-local field
Why this language

Pourquoi un compte à rebours ? C'est le widget qu'on voit sur toutes les pages d'événement, et il cache deux pièges : les fuseaux horaires, et le moment où la date est passée.

On calcule tout à partir de l'écart entre maintenant et la date visée, en millisecondes, puis on le découpe en jours, heures, minutes et secondes.

Pourquoi en JavaScript simple ? Une date, une soustraction, quatre divisions. C'est l'exercice parfait pour comprendre l'objet Date.

How it works
  1. LE HTML

    La date visée vit dans un attribut data- : le même script sert pour n'importe quel événement.

    <div class="rebours" data-cible="2026-12-18T20:00:00+01:00">
      <span id="j">0</span> j <span id="h">00</span> h <span id="m">00</span> min <span id="s">00</span> s
    </div>
  2. LA DATE VISÉE

    Le décalage horaire est écrit dans la date (+01:00 pour Bruxelles en hiver) : tout le monde vise le même instant.

    const bloc = document.querySelector('.rebours');
    const cible = new Date(bloc.dataset.cible);
    const el = id => document.getElementById(id);
  3. DÉCOUPER LE TEMPS

    Tout part des secondes restantes : 86 400 par jour, 3 600 par heure, 60 par minute.

    function decouper(ms) {
      const s = Math.floor(ms / 1000);
      return {
        j: Math.floor(s / 86400),
        h: Math.floor(s % 86400 / 3600),
        m: Math.floor(s % 3600 / 60),
        s: s % 60
      };
    }
  4. AFFICHER

    Deux chiffres pour les heures, minutes et secondes, et un message quand le moment est arrivé.

    const deux = n => String(n).padStart(2, '0');
    function afficher() {
      const reste = cible - Date.now();
      if (reste <= 0) {
        clearInterval(minuterie);
        bloc.textContent = "C'est maintenant.";
        return;
      }
      const t = decouper(reste);
      el('j').textContent = t.j;
      el('h').textContent = deux(t.h);
      el('m').textContent = deux(t.m);
      el('s').textContent = deux(t.s);
    }
  5. LANCER

    Un premier affichage tout de suite, puis une mise à jour par seconde.

    const minuterie = setInterval(afficher, 1000);
    afficher();
Pitfalls

PIÈGE 1 : Oublier le fuseau horaire

Pitfall

Mauvais : new Date('2026-12-18 20:00'). Chaque visiteur obtient 20 h dans SON fuseau : à Montréal, le compte à rebours tombe six heures trop tard.

Fix

Correct : écrire le décalage dans la date, 2026-12-18T20:00:00+01:00, pour viser le même instant partout.

PIÈGE 2 : Des nombres négatifs

Pitfall

Mauvais : laisser tourner le calcul après la date. On voit « -1 j -3 h ».

Fix

Correct : tester reste <= 0, arrêter la minuterie et afficher un message.

PIÈGE 3 : Une seconde de vide au chargement

Pitfall

Mauvais : se contenter de setInterval. La page affiche 0 pendant la première seconde.

Fix

Correct : appeler afficher() une fois tout de suite, puis laisser setInterval prendre le relais.

PERSONNALISER
  • Des libellés qui s'accordent : « 1 jour », « 2 jours », avec un petit test sur la valeur.
  • Plusieurs comptes à rebours sur la même page : un data-cible par bloc, et une boucle sur document.querySelectorAll('.rebours').
  • Un bouton « Ajouter à mon agenda » qui génère un fichier .ics avec la même date.
OPTIMISATION
  • Intl.RelativeTimeFormat écrit « dans 3 jours » dans la langue du visiteur, sans traduction à la main.
  • Quand il reste plus d'un jour, une mise à jour par minute suffit.
VERS REACT

La date visée arrive en prop, le temps restant vit dans un useState.

Le useEffect crée l'intervalle et le nettoie au démontage.

Le découpage se calcule pendant le rendu, à partir du temps restant : pas besoin de quatre états.

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.