Ressources pour développeur web

Théme de la semaine : Wordpress

Sélecteur de dates en CSS & JS : Tutoriel + code complet

Temps de lecture estimé : 8 minutes
Accueil CSS3 Sélecteur de dates en CSS & JS : Tutoriel + code complet

Coder un sélecteur de plage de dates en CSS et JavaScript est une compétence essentielle pour moderniser vos interfaces web. Dans ce tutoriel, vous allez apprendre à concevoir un calendrier interactif, élégant et responsive, capable de gérer une sélection de dates avec fluidité, sans utiliser de librairie externe. Un guide simple et complet pour maîtriser pas à pas la création d’un date range picker performant.

  • Coder un sélecteur de plage de dates moderne et fonctionnel sans dépendre de librairies externes
  • Améliorer l’expérience utilisateur avec des interactions fluides, des animations et une interface soignée
  • Acquérir des bases solides en JavaScript pour manipuler des dates à travers un cas concret réutilisable

Vous souhaitez permettre à vos utilisateurs de sélectionner une plage de dates sur votre site web, comme sur Booking ou Airbnb ? On va créer votre propre date range picker en HTML, CSS et JavaScript, sans aucune librairie externe. Dans ce tutoriel frontend, vous allez apprendre à construire ce fameux sélecteur de plage de dates élégant, moderne et interactif, en partant d’un exemple complet que vous pourrez réutiliser dans vos projets.

Comprendre le projet global

Avant de plonger dans le code, prenons 30 secondes pour comprendre ce que vous allez créer.

Votre composant permet de :

  • Naviguer entre les mois
  • Sélectionner une date de début
  • Sélectionner une date de fin
  • Visualiser la plage sélectionnée
  • Bloquer les dates passées
  • Offrir une interface fluide avec animations
Sélecteur de dates ou pick range

Autrement dit, vous recréez un mini calendrier intelligent.

Voici le résultat final :

L
M
M
J
V
S
D

Structure HTML : la base du calendrier

Commençons par la structure HTML. Rien de compliqué, mais chaque bloc a un rôle précis.

<div class="datepicker">
    <div class="header">
        <button id="prev">◀</button>
        <h3 id="monthYear"></h3>
        <button id="next">▶</button>
    </div>

    <div class="days">
        <div>L</div><div>M</div><div>M</div><div>J</div><div>V</div><div>S</div><div>D</div>
    </div>

    <div class="dates" id="dates"></div>

    <div class="footer" id="output">
        Sélectionnez une plage de dates
    </div>
</div>

Explication simple du code HTML :

  • .header : navigation entre les mois
  • .days : affichage des jours de la semaine
  • #dates : les jours du mois générés en JS
  • #output : affichage du résultat sélectionné

Vous avez donc une structure vide… et c’est JavaScript qui va tout animer.

Le design CSS : modernité et simplicité

Ici, vous avez utilisé une approche très propre avec des variables CSS :

:root {
    --primary: #4f46e5;
    --bg: #f9fafb;
    --text: #1f2937;
    --muted: #9ca3af;
    --range: #e0e7ff;
}

Pourquoi c’est utile ?

Parce que vous pouvez changer tout le design en quelques secondes. Par exemple :

  • changer la couleur principale
  • adapter au dark mode
  • harmoniser avec votre charte graphique

Le conteneur principal

.datepicker {
    background: var(--white);
    padding: 20px;
    border-radius: 16px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.05);
}

Résultat : un effet carte moderne type UI SaaS.

Les interactions visuelles

C’est là que ça devient intéressant.

Effet au survol

.date:hover {
    background: var(--range);
    transform: scale(1.05);
}

Vous donnez une sensation de vie à votre interface. Sans ça, votre calendrier serait… triste.

Animation d’apparition

@keyframes fadeSlide {
    from {
        opacity: 0;
        transform: translateY(10px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

Chaque changement de mois est fluide. C’est un détail… mais c’est ce qui fait la différence.

JavaScript : le cerveau du calendrier

Maintenant, passons au cœur du système.

Variables principales

let currentDate = new Date();
let startDate = null;
let endDate = null;
  • currentDate : mois affiché
  • startDate : début sélection
  • endDate : fin sélection

Génération du calendrier

La fonction clé :

function renderCalendar(date) {

Ce qu’elle fait

  1. Vide le calendrier
  2. Calcule :
    • le premier jour du mois
    • le nombre de jours
  3. Génère chaque case jour
  4. Applique les styles (sélection, range, désactivé)

Calcul du nombre de jours

const daysInMonth = new Date(year, month + 1, 0).getDate();

Astuce JavaScript :

  • jour 0 du mois suivant = dernier jour du mois actuel

Oui, c’est un hack… mais un hack officiel 😄

Formation web et informatique - Alban Guillier - Formateur

Des formations informatique pour tous !

Débutant ou curieux ? Apprenez le développement web, le référencement, le webmarketing, la bureautique, à maîtriser vos appareils Apple et bien plus encore...

Formateur indépendant, professionnel du web depuis 2006, je vous accompagne pas à pas et en cours particulier, que vous soyez débutant ou que vous souhaitiez progresser. En visio, à votre rythme, et toujours avec pédagogie.

Découvrez mes formations Qui suis-je ?

Bloquer les dates passées

if (fullDate < today) {
    div.classList.add("disabled");
}

Pourquoi c’est important ?

  • Empêcher des réservations invalides
  • Éviter les erreurs utilisateur
  • Améliorer l’expérience

Sélection de la plage de dates

Voici la logique :

function selectDate(date) {

Cas 1 : aucune date sélectionnée

  • On définit la date de début

Cas 2 : une date déjà choisie

  • On définit la fin

Cas 3 : l’utilisateur clique avant la date de début

  • On inverse automatiquement

Résultat : Une UX ultra fluide !

Mise en évidence de la plage

if (startDate && endDate && fullDate > startDate && fullDate < endDate) {
    div.classList.add("in-range");
}

Effet visuel

  • Début : couleur principale
  • Fin : couleur principale
  • Entre les deux : couleur douce

C’est exactement le comportement attendu par les utilisateurs.

Affichage du résultat

output.textContent = `${formatDate(startDate)} → ${formatDate(endDate)}`;

Format français

date.toLocaleDateString("fr-FR");

Simple, efficace, localisé.

Navigation entre les mois

currentDate.setMonth(currentDate.getMonth() + 1);

JavaScript gère automatiquement :

  • changement d’année
  • mois négatifs
  • transitions

Responsive design

@media (max-width: 400px)

Votre calendrier reste utilisable sur mobile grâce aux media query en CSS.

Et ça, croyez-moi, c’est non négociable aujourd’hui.

Ce que vous avez appris : Le résumé

En construisant ce projet, vous avez manipulé :

  • Le DOM en JavaScript
  • Les dates en JS (pas simple !)
  • Les événements utilisateur
  • Les animations CSS
  • L’UX design
  • La logique conditionnelle

Autrement dit… vous avez fait un vrai projet pro.

Le code complet HTML + CSS + JS

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Date Range Picker</title>

<style>
:root {
    --primary: #4f46e5;
    --bg: #f9fafb;
    --text: #1f2937;
    --muted: #9ca3af;
    --range: #e0e7ff;
    --white: #ffffff;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, sans-serif;
    background: var(--bg);
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
}

/* Container */
.datepicker {
    background: var(--white);
    padding: 20px;
    border-radius: 16px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.05);
    width: 320px;
    max-width: 95%;
}

/* Header */
.header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 15px;
}

.header button {
    background: none;
    border: none;
    font-size: 18px;
    cursor: pointer;
    color: var(--text);
    transition: transform 0.2s ease;
}

.header button:hover {
    transform: scale(1.2);
}

.header h3 {
    margin: 0;
    font-size: 16px;
}

/* Days */
.days, .dates {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    text-align: center;
}

.days div {
    font-size: 12px;
    color: var(--muted);
    margin-bottom: 5px;
}

/* Animation container */
.dates {
    animation: fadeSlide 0.3s ease;
}

@keyframes fadeSlide {
    from {
        opacity: 0;
        transform: translateY(10px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* Date cells */
.date {
    padding: 10px;
    margin: 2px;
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.2s ease;
}

.date:hover {
    background: var(--range);
    transform: scale(1.05);
}

.selected {
    background: var(--primary);
    color: white;
}

.in-range {
    background: var(--range);
}

/* Disabled past dates */
.disabled {
    color: #d1d5db;
    pointer-events: none;
    background: transparent;
}

/* Footer */
.footer {
    margin-top: 15px;
    font-size: 14px;
    text-align: center;
    color: var(--text);
}

/* Responsive */
@media (max-width: 400px) {
    .datepicker {
        padding: 15px;
    }
    .date {
        padding: 8px;
    }
}
</style>
</head>

<body>

<div class="datepicker">
    <div class="header">
        <button id="prev">◀</button>
        <h3 id="monthYear"></h3>
        <button id="next">▶</button>
    </div>

    <div class="days">
        <div>L</div><div>M</div><div>M</div><div>J</div><div>V</div><div>S</div><div>D</div>
    </div>

    <div class="dates" id="dates"></div>

    <div class="footer" id="output">
        Sélectionnez une plage de dates
    </div>
</div>

<script>
const datesContainer = document.getElementById("dates");
const monthYear = document.getElementById("monthYear");
const output = document.getElementById("output");

let currentDate = new Date();
let startDate = null;
let endDate = null;

// Aujourd'hui sans heure
const today = new Date();
today.setHours(0,0,0,0);

function renderCalendar(date) {
    datesContainer.innerHTML = "";
    const year = date.getFullYear();
    const month = date.getMonth();

    const firstDay = new Date(year, month, 1).getDay();
    const daysInMonth = new Date(year, month + 1, 0).getDate();

    const monthNames = ["Janvier","Février","Mars","Avril","Mai","Juin",
                        "Juillet","Août","Septembre","Octobre","Novembre","Décembre"];

    monthYear.textContent = `${monthNames[month]} ${year}`;

    let startOffset = (firstDay === 0 ? 6 : firstDay - 1);

    for (let i = 0; i < startOffset; i++) {
        datesContainer.innerHTML += `<div></div>`;
    }

    for (let day = 1; day <= daysInMonth; day++) {
        const fullDate = new Date(year, month, day);
        fullDate.setHours(0,0,0,0);

        const div = document.createElement("div");
        div.classList.add("date");
        div.textContent = day;

        // Bloquer dates passées
        if (fullDate < today) {
            div.classList.add("disabled");
        } else {
            div.addEventListener("click", () => selectDate(fullDate));
        }

        if (startDate && sameDate(fullDate, startDate)) {
            div.classList.add("selected");
        }

        if (endDate && sameDate(fullDate, endDate)) {
            div.classList.add("selected");
        }

        if (startDate && endDate && fullDate > startDate && fullDate < endDate) {
            div.classList.add("in-range");
        }

        datesContainer.appendChild(div);
    }
}

function selectDate(date) {
    if (!startDate || (startDate && endDate)) {
        startDate = date;
        endDate = null;
    } else {
        if (date < startDate) {
            endDate = startDate;
            startDate = date;
        } else {
            endDate = date;
        }
    }
    updateOutput();
    renderCalendar(currentDate);
}

function sameDate(d1, d2) {
    return d1.toDateString() === d2.toDateString();
}

function updateOutput() {
    if (startDate && endDate) {
        output.textContent = `${formatDate(startDate)} → ${formatDate(endDate)}`;
    } else if (startDate) {
        output.textContent = `Début : ${formatDate(startDate)}`;
    }
}

function formatDate(date) {
    return date.toLocaleDateString("fr-FR");
}

document.getElementById("prev").onclick = () => {
    currentDate.setMonth(currentDate.getMonth() - 1);
    renderCalendar(currentDate);
};

document.getElementById("next").onclick = () => {
    currentDate.setMonth(currentDate.getMonth() + 1);
    renderCalendar(currentDate);
};

renderCalendar(currentDate);
</script>

</body>
</html>

Aller plus loin : idées d'amélioration

Si vous voulez pousser ce composant encore plus loin :

  • Ajouter un bouton "Réinitialiser"
  • Bloquer certaines plages (week-ends, jours fériés)
  • Ajouter une heure (datetime picker)
  • Synchroniser avec une API (réservation)
  • Ajouter un mode sombre
  • Etc...

Vous venez de créer un sélecteur de plage de dates moderne en CSS et JavaScript, entièrement personnalisé, sans dépendance externe. Et surtout, vous avez compris comment il fonctionne.

Ce type de composant est un excellent exercice : il mélange logique, design et interaction utilisateur. C’est exactement ce qu’on vous demandera dans des projets réels.

La prochaine étape ? L’intégrer dans un vrai projet !

Et entre nous… quand vous commencez à coder ce genre de composant sans copier-coller, vous n’êtes plus débutant.