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.

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.
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
Commence par la calculatrice en HTML, CSS et JavaScript : un projet plus court pour découvrir les fonctions et le DOM.
Arborescence du projet
É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.htmlCe que contient ce code
- Dans le <head> : Bootstrap, les icônes Font Awesome et ta feuille
style.css - Le conteneur : la classe
containerde Bootstrap centre le contenu, etmt-5ajoute une marge en haut - Le champ et le bouton :
#taskInputpour saisir la tâche et#addTaskButtonpour l’ajouter - La liste : un
<ul id="taskList">qui recevra chaque tâche - Les scripts : Bootstrap, puis ton fichier
app.jsen 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.jsComment fonctionne ce code
prompt() pour modifier le texte.confirm(), puis retire la tâche avec splice().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.htmldans 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.jsD’autres idées pour faire évoluer ton application de gestion de tâches :
- Ajouter des filtres : toutes, en cours, terminées
- Remplacer
prompt()par une modification directement dans la liste - Ajouter une date d’échéance et une priorité à chaque tâche
- Passer à une vraie base de données avec PHP et MySQL, comme dans le tutoriel créer une application de planning en PHP et MySQL
- Continuer à pratiquer avec la Quiz App en JavaScript ou le générateur de citations et proverbes
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.

