Écran d'ordinateur affichant du code HTML et JavaScript

Comment faire un quiz en HTML et JavaScript ?

Publié le

Un quiz interactif est un excellent exercice pour pratiquer HTML, CSS et JavaScript. Dans ce tutoriel, nous allons construire pas à pas un quiz à choix multiples : l'utilisateur sélectionne une réponse par question, clique sur « Valider » et voit immédiatement les bonnes et mauvaises réponses surlignées, ainsi que son score. Il peut ensuite tout réinitialiser pour recommencer.

Partie 1 : Structure HTML

1.1 Le squelette de la page et le conteneur principal

On commence par une page HTML standard. Tout le quiz sera regroupé dans une div.quiz-container centrée, qui contiendra l'introduction, les questions, les boutons d'action et la zone de résultat.

<!DOCTYPE html>
<html lang="fr">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Quiz simple</title>
  </head>
  <body>
    <div class="quiz-container">
      <!-- tout le quiz ira ici -->
    </div>
  </body>
</html>

1.2 La section d'introduction

On ajoute une section .introduction avec un titre h1 et un court paragraphe explicatif.

<section class="introduction">
  <h1>Quiz de démo</h1>
  <p>
    Choisis une réponse par question puis clique sur « Valider ».
    Les bonnes et mauvaises réponses seront surlignées.
  </p>
</section>

1.3 Structure d'une question

Chaque question est un article.question-block avec un attribut data-question-id unique. À l'intérieur :

  • Une div.question-text pour le texte de la question.
  • Une div.options-container pour les réponses.

Chaque option est un label.option-label (rend toute la ligne cliquable) contenant :

  • Une div.option-content qui aligne les éléments.
  • Un span.option-letter (A., B., C…).
  • Un input type="radio" avec le même name pour toutes les options d'une question, et l'attribut data-correct="true" sur la bonne réponse.
  • Un span.option-text pour le texte de la réponse.
<section class="articles-container">

  <!-- Question 1 -->
  <article class="question-block" data-question-id="q1">
    <div class="question-text">
      1. Quelle balise HTML est utilisée pour créer un lien hypertexte ?
    </div>
    <div class="options-container">

      <label class="option-label">
        <div class="option-content">
          <span class="option-letter">A.</span>
          <input type="radio" name="q1" value="a" />
          <span class="option-text">&lt;link&gt;</span>
        </div>
      </label>

      <label class="option-label">
        <div class="option-content">
          <span class="option-letter">B.</span>
          <input type="radio" name="q1" value="b" data-correct="true" />
          <span class="option-text">&lt;a&gt;</span>
        </div>
      </label>

      <label class="option-label">
        <div class="option-content">
          <span class="option-letter">C.</span>
          <input type="radio" name="q1" value="c" />
          <span class="option-text">&lt;href&gt;</span>
        </div>
      </label>

    </div>
  </article>

  <!-- Question 2 : même structure, name="q2", data-correct sur la bonne réponse -->
  <article class="question-block" data-question-id="q2">
    <div class="question-text">
      2. Quel type d'input HTML permet de créer un bouton radio ?
    </div>
    <div class="options-container">

      <label class="option-label">
        <div class="option-content">
          <span class="option-letter">A.</span>
          <input type="radio" name="q2" value="a" />
          <span class="option-text">input type="checkbox"</span>
        </div>
      </label>

      <label class="option-label">
        <div class="option-content">
          <span class="option-letter">B.</span>
          <input type="radio" name="q2" value="b" data-correct="true" />
          <span class="option-text">input type="radio"</span>
        </div>
      </label>

      <label class="option-label">
        <div class="option-content">
          <span class="option-letter">C.</span>
          <input type="radio" name="q2" value="c" />
          <span class="option-text">input type="button"</span>
        </div>
      </label>

    </div>
  </article>

</section>

Pour ajouter une troisième question, il suffit de dupliquer un article.question-block, de changer data-question-id en q3, de mettre name="q3" sur les radios, et de placer data-correct="true" sur la bonne réponse.

1.4 Les boutons d'action et la zone de résultat

En dehors du conteneur de questions, on ajoute la barre d'actions et un bloc de résultat vide au départ.

<div class="quiz-actions">
  <button id="reset-quiz" class="secondary">Réinitialiser</button>
  <button id="validate-quiz">Valider</button>
</div>

<div id="quiz-result"></div>

Partie 2 : CSS

Le CSS ci-dessous couvre uniquement ce qui est nécessaire au bon fonctionnement visuel du quiz : mise en page des questions, alignement des options, et coloration des états correct / incorrect. Tu peux l'enrichir à ta guise.

/* --- Conteneur global --- */
.quiz-container {
  max-width: 900px;
  margin: 0 auto;
  padding: 0 16px;
}

/* --- Bloc question --- */
.question-block {
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 6px rgba(0,0,0,.05);
  padding: 16px 12px;
  margin-bottom: 24px;
}

/* --- Texte de la question --- */
.question-text {
  font-weight: 600;
  color: #2c3e50;
  border-bottom: 1px solid #e3e9f5;
  padding-bottom: 8px;
  margin-bottom: 14px;
}

/* --- Liste d'options --- */
.options-container {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* --- Ligne d'option cliquable --- */
.option-label {
  display: flex;
  background: #f5f7fa;
  border: 1px solid transparent;
  border-radius: 8px;
  padding: 8px 10px;
  cursor: pointer;
  transition: background-color .25s, border-color .25s;
}

.option-content {
  display: flex;
  align-items: center;
  width: 100%;
}

.option-letter {
  font-weight: bold;
  min-width: 22px;
  margin-right: 10px;
  color: #555;
}

.option-label input[type="radio"] {
  margin-right: 10px;
  transform: scale(1.1);
  cursor: pointer;
  flex-shrink: 0;
}

.option-text {
  flex: 1;
  color: #333;
  overflow-wrap: break-word;
}

/* --- États après correction --- */
.option-label.selected-correct {
  background-color: #e6ffed;
  border-color: #28a745;
}

.option-label.selected-incorrect {
  background-color: #ffe6e6;
  border-color: #dc3545;
}

/* --- Zone de résultat global --- */
#quiz-result {
  display: none;          /* caché par défaut */
  margin: 20px auto;
  padding: 16px;
  border-radius: 8px;
  background: #f0f4f8;
  font-weight: 600;
  text-align: center;
  box-shadow: 0 2px 8px rgba(0,0,0,.1);
}

/* --- Boutons --- */
.quiz-actions {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}

.quiz-actions button {
  padding: 10px 18px;
  border-radius: 6px;
  border: none;
  background-color: #0069d9;
  color: #fff;
  font-weight: 600;
  cursor: pointer;
}

.quiz-actions button.secondary {
  background-color: #6c757d;
}

/* --- Responsive mobile --- */
@media (max-width: 480px) {
  .quiz-actions {
    flex-direction: column;
  }
  .quiz-actions button {
    width: 100%;
  }
}

Partie 3 : JavaScript

3.1 Récupérer les éléments du DOM

On commence par cibler les éléments dont on aura besoin tout au long du script, et on crée une fonction utilitaire pour récupérer tous les blocs de questions.

const validateButton = document.getElementById('validate-quiz');
const resetButton    = document.getElementById('reset-quiz');
const resultBox      = document.getElementById('quiz-result');

function getQuestionBlocks() {
  return document.querySelectorAll('.question-block');
}

3.2 Vérifier que toutes les questions ont une réponse

Avant de corriger le quiz, on s'assure que chaque bloc contient au moins un radio coché. Si ce n'est pas le cas, on affiche un message d'erreur et on arrête l'exécution avec return.

function allQuestionsAnswered() {
  for (const block of getQuestionBlocks()) {
    const checked = block.querySelector('input[type="radio"]:checked');
    if (!checked) return false;
  }
  return true;
}

validateButton.addEventListener('click', () => {
  if (!allQuestionsAnswered()) {
    resultBox.style.display = 'block';
    resultBox.textContent   = 'Tu dois répondre à toutes les questions avant de valider.';
    return; // on arrête ici
  }
  // … suite de la correction
});

3.3 Calculer le score et colorier les réponses

Pour chaque question, on retire d'abord les classes d'état précédentes, puis on récupère la réponse cochée. Si elle porte l'attribut data-correct, c'est une bonne réponse : on ajoute selected-correct et on incrémente le score. Sinon on ajoute selected-incorrect sur le choix de l'utilisateur, et selected-correct sur la vraie bonne réponse.

// (dans le callback du bouton Valider, après le garde allQuestionsAnswered)
const questionBlocks = getQuestionBlocks();
let total = questionBlocks.length;
let score = 0;

questionBlocks.forEach(block => {

  // 1. Nettoyer les classes d'état précédentes
  block.querySelectorAll('.option-label').forEach(label => {
    label.classList.remove('selected-correct', 'selected-incorrect');
  });

  // 2. Récupérer la réponse sélectionnée
  const selectedInput = block.querySelector('input[type="radio"]:checked');
  const label         = selectedInput.closest('.option-label');
  const isCorrect     = selectedInput.hasAttribute('data-correct');

  // 3. Appliquer les classes et calculer le score
  if (isCorrect) {
    score++;
    label.classList.add('selected-correct');
  } else {
    label.classList.add('selected-incorrect');
    // Afficher aussi la bonne réponse
    const correctInput = block.querySelector('input[data-correct]');
    if (correctInput) {
      correctInput.closest('.option-label').classList.add('selected-correct');
    }
  }
});

// 4. Afficher le résultat
resultBox.style.display = 'block';
resultBox.textContent   = `Tu as ${score} bonne(s) réponse(s) sur ${total}.`;

3.4 Bloquer les radios après validation

Une fois la correction affichée, on désactive tous les boutons radio pour empêcher l'utilisateur de modifier ses réponses.

function setRadiosDisabled(disabled) {
  document.querySelectorAll('input[type="radio"]').forEach(radio => {
    radio.disabled = disabled;
  });
}

// Appel à la fin du traitement de validation :
setRadiosDisabled(true);

3.5 Réinitialiser le quiz

Le bouton « Réinitialiser » décoche tous les radios, les réactive, supprime les classes d'état et masque la zone de résultat.

function clearSelections() {
  document.querySelectorAll('input[type="radio"]').forEach(radio => {
    radio.checked  = false;
    radio.disabled = false;
  });
  document.querySelectorAll('.option-label').forEach(label => {
    label.classList.remove('selected-correct', 'selected-incorrect');
  });
  resultBox.style.display = 'none';
  resultBox.textContent   = '';
}

resetButton.addEventListener('click', () => {
  clearSelections();
});

3.6 Script complet

Voici le script JavaScript dans son intégralité, tel qu'il doit être placé juste avant la balise </body>.

const validateButton = document.getElementById('validate-quiz');
const resetButton    = document.getElementById('reset-quiz');
const resultBox      = document.getElementById('quiz-result');

function getQuestionBlocks() {
  return document.querySelectorAll('.question-block');
}

function allQuestionsAnswered() {
  for (const block of getQuestionBlocks()) {
    if (!block.querySelector('input[type="radio"]:checked')) return false;
  }
  return true;
}

function setRadiosDisabled(disabled) {
  document.querySelectorAll('input[type="radio"]')
    .forEach(r => r.disabled = disabled);
}

function clearSelections() {
  document.querySelectorAll('input[type="radio"]').forEach(r => {
    r.checked = false; r.disabled = false;
  });
  document.querySelectorAll('.option-label').forEach(l =>
    l.classList.remove('selected-correct', 'selected-incorrect')
  );
  resultBox.style.display = 'none';
  resultBox.textContent   = '';
}

validateButton.addEventListener('click', () => {
  if (!allQuestionsAnswered()) {
    resultBox.style.display = 'block';
    resultBox.textContent   = 'Tu dois répondre à toutes les questions avant de valider.';
    return;
  }

  const questionBlocks = getQuestionBlocks();
  let score = 0;

  questionBlocks.forEach(block => {
    block.querySelectorAll('.option-label').forEach(l =>
      l.classList.remove('selected-correct', 'selected-incorrect')
    );

    const selected  = block.querySelector('input[type="radio"]:checked');
    const label     = selected.closest('.option-label');
    const isCorrect = selected.hasAttribute('data-correct');

    if (isCorrect) {
      score++;
      label.classList.add('selected-correct');
    } else {
      label.classList.add('selected-incorrect');
      const correct = block.querySelector('input[data-correct]');
      if (correct) correct.closest('.option-label').classList.add('selected-correct');
    }
  });

  resultBox.style.display = 'block';
  resultBox.textContent   = `Tu as ${score} bonne(s) réponse(s) sur ${questionBlocks.length}.`;
  setRadiosDisabled(true);
});

resetButton.addEventListener('click', clearSelections);

Quiz interactif

Voici le quiz en action. Choisis une réponse par question, puis clique sur « Valider » pour voir ta correction et ton score.

Quiz de démo

Choisis une réponse par question puis clique sur « Valider ».

1. Quelle balise HTML est utilisée pour créer un lien hypertexte ?
2. Quel type d'input HTML permet de créer un bouton radio ?
3. Quel attribut JavaScript indique qu'une option est la bonne réponse dans notre quiz ?

Sources

Mots clés

HTML JavaScript
Un écran affichant du code avec des projets en cours de développement Apprendre à coder : 12 idées d'applications à créer soi-même

To-do list, app météo, messagerie instantanée… 12 projets concrets pour progresser vraiment en codant, du CRUD débutant aux WebSockets avancés.

Un écran affichant un décompte numérique Créer un compte à rebours avec JavaScript

Découvrez comment créer un compte à rebours en JavaScript avec setInterval, setTimeout et requestAnimationFrame, et apprenez quelle méthode choisir selon votre cas d'usage.

Une personne en train de taper sur le clavier d'un ordinateur portable Créer une barre de recherche interactive avec JavaScript

Découvrez comment créer une barre de recherche interactive avec HTML et JavaScript. Tutoriel étape par étape.