Dans ce tutoriel, tu vas créer une application de gestion de tâches en JavaScript, avec HTML et Bootstrap : ajouter, modifier, cocher et supprimer des tâches, le tout sauvegardé automatiquement dans le navigateur. Une to-do list moderne et un excellent projet pour pratiquer le DOM, les événements et le stockage local.

Niveau : débutantDurée : ~1 hHTML · Bootstrap 5 · JavaScriptCode source gratuit
Application de gestion de tâches en JavaScript avec Bootstrap : liste de tâches avec boutons
Le résultat final : une to-do list avec boutons Terminer, Modifier et Supprimer

Ce que tu vas construire : une application de gestion de tâches complète

Une to-do list est le grand classique pour progresser en JavaScript : simple à comprendre, elle couvre pourtant toutes les bases d’une vraie application. Celle-ci est un point de départ solide que tu pourras enrichir selon tes envies.

➕ AjouterSaisis une tâche et valide avec le bouton ou la touche Entrée.
✅ TerminerCoche une tâche pour la marquer comme faite.
✏️ ModifierChange le texte d’une tâche existante.
💾 Sauvegarde autoLes tâches restent en mémoire grâce au localStorage.

Prérequis

  • Les bases de HTML et de JavaScript (variables, fonctions, tableaux)
  • Un éditeur de code comme Visual Studio Code et un navigateur récent
  • Aucune installation : Bootstrap et les icônes Font Awesome sont chargés via CDN
💡
Nouveau en JavaScript ?

Commence par la calculatrice en HTML, CSS et JavaScript : un projet plus court pour découvrir les fonctions et le DOM.

Arborescence du projet

to-do-list/ ├── index.html # structure de l’application ├── style.css # touche visuelle personnalisée └── app.js # logique : ajout, modification, sauvegarde

Étape 1 : la structure HTML

Le fichier index.html contient un champ pour saisir une tâche, un bouton « Ajouter » et une liste qui affichera toutes les tâches. Crée-le avec ce code :

<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>📝 Gestionnaire de Tâches</title>

  <!-- Bootstrap 5 -->
  <link
    href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
    rel="stylesheet"
  >
  <!-- FontAwesome -->
  <link
    rel="stylesheet"
    href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
    crossorigin="anonymous"
  >
  <link rel="stylesheet" href="style.css">
</head>
<body class="bg-light">

  <div class="container py-5">
    <h1 class="text-center mb-4">🗒️ Mon Gestionnaire de Tâches</h1>

    <!-- Formulaire d'ajout -->
    <div class="row justify-content-center mb-4">
      <div class="col-md-8">
        <div class="input-group shadow-sm">
          <span class="input-group-text bg-white">
            <i class="fas fa-smile-beam"></i>
          </span>
          <input
            type="text"
            id="taskInput"
            class="form-control form-control-lg"
            placeholder="Quelle est ta prochaine mission ?"
            aria-label="Nouvelle tâche"
          >
          <button class="btn btn-primary btn-lg" id="addTaskButton" aria-label="Ajouter tâche">
            <i class="fas fa-plus me-2"></i>Ajouter
          </button>
        </div>
      </div>
    </div>

    <!-- Liste des tâches -->
    <div class="row justify-content-center">
      <div class="col-md-8">
        <ul class="list-group" id="taskList"></ul>
      </div>
    </div>
  </div>

  <!-- Bootstrap Bundle (Popper + JS) -->
  <script
    src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
  ></script>
  <script src="app.js"></script>
</body>
</html>
index.html

Ce que contient ce code

  • Dans le <head> : Bootstrap, les icônes Font Awesome et ta feuille style.css
  • Le conteneur : la classe container de Bootstrap centre le contenu, et mt-5 ajoute une marge en haut
  • Le champ et le bouton : #taskInput pour saisir la tâche et #addTaskButton pour l’ajouter
  • La liste : un <ul id="taskList"> qui recevra chaque tâche
  • Les scripts : Bootstrap, puis ton fichier app.js en fin de page

Étape 2 : la touche visuelle avec style.css

Bootstrap fait déjà le gros du travail. Ce petit fichier style.css ajoute les ombres, l’effet de survol et le style des tâches terminées :

/* Liste et style général */
.list-group-item {
  border-radius: 0.5rem;
  margin-bottom: 0.5rem;
  box-shadow: 0 2px 6px rgba(0,0,0,0.1);
  transition: transform 0.1s, background-color 0.2s;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

/* Hover léger */
.list-group-item:hover {
  transform: translateY(-2px);
  background-color: #f8f9fa;
}

/* Emoji */
.task-emoji {
  font-size: 1.5rem;
  margin-right: 0.75rem;
}

/* Texte barré si terminé */
.list-group-item.completed .task-text {
  text-decoration: line-through;
  opacity: 0.6;
}

/* Groupe de boutons toujours visible */
.btn-actions > .btn {
  margin-left: 0.25rem;
}

/* Styles des boutons d’action */
.btn-complete {
  color: #fff;
  background-color: #28a745;
}
.btn-edit {
  color: #fff;
  background-color: #ffc107;
}
.btn-delete {
  color: #fff;
  background-color: #dc3545;
}

/* Ajustements mobile */
@media (max-width: 576px) {
  .task-emoji { font-size: 1.25rem; }
  .btn-actions .btn {
    padding: 0.25rem 0.5rem;
    font-size: 0.8rem;
  }
}
style.css

Étape 3 : la logique JavaScript (app.js)

C’est ici que ton application de gestion de tâches prend vie. Crée le fichier app.js avec ce code :

document.addEventListener("DOMContentLoaded", () => {
  const taskInput     = document.getElementById("taskInput");
  const addTaskButton = document.getElementById("addTaskButton");
  const taskList      = document.getElementById("taskList");

  const EMOJIS = ["😀","😎","😉","🔥","🚀","🌟","💡","🎉","✅","📌"];
  let tasks = JSON.parse(localStorage.getItem("tasks") || "[]");
  renderTasks();

  addTaskButton.addEventListener("click", addTask);
  taskInput.addEventListener("keypress", e => {
    if (e.key === "Enter") addTask();
  });

  function saveTasks() {
    localStorage.setItem("tasks", JSON.stringify(tasks));
  }

  function addTask() {
    const text = taskInput.value.trim();
    if (!text) return;
    const emoji = EMOJIS[Math.floor(Math.random()*EMOJIS.length)];
    tasks.push({ text, emoji, done: false });
    taskInput.value = "";
    saveTasks();
    renderTasks();
  }

  function toggleDone(idx) {
    tasks[idx].done = !tasks[idx].done;
    saveTasks();
    renderTasks();
  }

  function editTask(idx) {
    const newText = prompt("Modifier la tâche :", tasks[idx].text);
    if (newText !== null && newText.trim()) {
      tasks[idx].text = newText.trim();
      saveTasks();
      renderTasks();
    }
  }

  function deleteTask(idx) {
    if (confirm("Supprimer cette tâche ?")) {
      tasks.splice(idx, 1);
      saveTasks();
      renderTasks();
    }
  }

  function renderTasks() {
    taskList.innerHTML = "";
    tasks.forEach((task, idx) => {
      const li = document.createElement("li");
      li.className = `list-group-item ${task.done ? "completed" : ""}`;

      // Emoji + texte cliquable
      const leftDiv = document.createElement("div");
      leftDiv.className = "d-flex align-items-center";
      const spanEmoji = document.createElement("span");
      spanEmoji.className = "task-emoji";
      spanEmoji.textContent = task.emoji;
      const textSpan = document.createElement("span");
      textSpan.className = "task-text";
      textSpan.textContent = task.text;
      textSpan.style.cursor = "pointer";
      textSpan.addEventListener("click", () => toggleDone(idx));
      leftDiv.append(spanEmoji, textSpan);

      // Boutons d’action
      const btnGroup = document.createElement("div");
      btnGroup.className = "btn-actions";

      const btnDone = document.createElement("button");
      btnDone.className = "btn btn-complete btn-sm";
      btnDone.innerHTML = `<i class="fas fa-check me-1"></i>OK`;
      btnDone.title = "Terminer";
      btnDone.addEventListener("click", () => toggleDone(idx));

      const btnEdit = document.createElement("button");
      btnEdit.className = "btn btn-edit btn-sm";
      btnEdit.innerHTML = `<i class="fas fa-pen me-1"></i>Mod`;
      btnEdit.title = "Modifier";
      btnEdit.addEventListener("click", () => editTask(idx));

      const btnDelete = document.createElement("button");
      btnDelete.className = "btn btn-delete btn-sm";
      btnDelete.innerHTML = `<i class="fas fa-trash me-1"></i>Sup`;
      btnDelete.title = "Supprimer";
      btnDelete.addEventListener("click", () => deleteTask(idx));

      btnGroup.append(btnDone, btnEdit, btnDelete);

      li.append(leftDiv, btnGroup);
      taskList.appendChild(li);
    });
  }
});
app.js

Comment fonctionne ce code

tasks + localStorageLes tâches sont stockées dans un tableau, rechargé depuis le navigateur au démarrage.
addTask()Vérifie que le texte n’est pas vide, ajoute la tâche avec un emoji aléatoire, puis sauvegarde.
toggleDone()Inverse l’état « terminé » d’une tâche.
editTask()Ouvre une boîte prompt() pour modifier le texte.
deleteTask()Demande confirmation avec confirm(), puis retire la tâche avec splice().
renderTasks()Vide la liste et la reconstruit entièrement à partir du tableau.
ℹ️
Pourquoi tout redessiner avec renderTasks() ?

Plutôt que de modifier la page élément par élément, on met à jour le tableau tasks, puis on régénère la liste. Les données restent la seule source de vérité : c’est le même principe que dans React ou Vue.

Étape 4 : tester ton application

  • Ouvre index.html dans ton navigateur
  • Ajoute plusieurs tâches, avec le bouton puis avec la touche Entrée
  • Coche, modifie et supprime des tâches
  • Recharge la page : tes tâches sont toujours là grâce au localStorage

Aller plus loin

Afficher un compteur de tâches restantes

Ajoute un élément <p id="counter"></p> sous la liste dans index.html, puis appelle cette fonction à la fin de renderTasks() :

function updateCounter() {
  const remaining = tasks.filter(task => !task.done).length;
  document.getElementById('counter').textContent =
    remaining + ' tâche(s) restante(s)';
}
app.js

D’autres idées pour faire évoluer ton application de gestion de tâches :

FAQ : questions fréquentes

Où sont enregistrées mes tâches ?

Dans le localStorage de ton navigateur. Elles restent disponibles après un rechargement, mais uniquement sur cet ordinateur et ce navigateur. Vider les données du site les efface.

Pourquoi mes tâches disparaissent-elles en navigation privée ?

En navigation privée, le localStorage est effacé à la fermeture de la fenêtre. C’est le comportement normal du navigateur.

Puis-je utiliser cette application sans Bootstrap ?

Oui. Bootstrap ne gère que l’apparence. Il suffit de remplacer ses classes par ton propre CSS : la logique JavaScript reste identique.

Comment partager mes tâches entre plusieurs appareils ?

Il faut un back-end : un serveur (PHP, Node.js ou Python) et une base de données qui stockent les tâches, et une API que ton JavaScript appelle avec fetch().

Bravo, ton application de gestion de tâches est terminée ! Tu sais maintenant manipuler le DOM, gérer des événements et sauvegarder des données dans le navigateur. Une question ou une amélioration à partager ? Laisse un commentaire ci-dessous.

Comments

No comments yet. Why don’t you start the discussion?

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *