Projects


Edgar Allan is working on a large Webflow project that includes authentication, URL rewrites, API connections, and a quiz. Webflow isn’t well-suited for much of this functionality. To achieve everything the client wants, we utilized a tool we built called Wes. Wes allows us to work within Webflow Enterprise while managing deployment using the tech stack of your choice.

Recently, we’ve had conversations with several Webflow agencies to unblock them. If you’re facing limitations with functionality you can’t support, let us know—we might be able to help.

And a quiz? Yes, we developed an initial draft of the quiz functionality and added 25 JavaScript questions. You can test your Javascript knowledge and let's discuss how we built the quiz functionality.

✍️ Take the Javascript quiz

Javascript 101: Building a quiz

Our quiz app required the following:

  • The ability to fetch a list of questions.
  • Store questions in localStorage to retain the users answers.
  • Allow navigation through quiz questions.
  • Show progress using a progress bar.
  • Display results at the end with correct and incorrect answers highlighted.

Step 1: Setup and Initialization

The quiz initializes by checking if questions are already stored in localStorage. If not, it fetches them from a JSON file. You can see that here.

let currentQuestionIndex = 0;
let correctAnswersCount = 0;
let questions = JSON.parse(localStorage.getItem("questions"));

async function fetchQuestions() {
try {
const response = await fetch("/questions.json");
const data = await response.json();
questions = data;
localStorage.setItem("questions", JSON.stringify(questions));
runQuiz(); // Start the quiz after fetching questions
} catch (error) {
console.error("Error fetching questions:", error);
}
}

if (!questions) {
console.log("fetching questions");
fetchQuestions();
} else {
console.log("running quiz");
runQuiz();
}

Step 2: Running the Quiz

The runQuiz function manages the quiz’s main functionality: displaying questions, handling navigation, and showing results.

This code retrieves references to essential DOM elements and then defines functionality.

code const questionSection = document.querySelector(“.question-section”);
const resultsSection = document.querySelector(“.results-section”);

const questionTitle = document.getElementById(“question-title”);
const questionText = document.getElementById(“question-text”);
const answersContainer = document.getElementById(“answers”);
const progressBar = document.getElementById(“progressBar”);

const prevBtn = document.getElementById(“prevBtn”);
const nextBtn = document.getElementById(“nextBtn”);

// Functions come next...

Step 3: Displaying a Question

The updateQuestion function updates the quiz UI with the current question, its options, and the progress bar.

function updateQuestion() {
const currentQuestion = questions[currentQuestionIndex];
questionTitle.textContent = `Question ${currentQuestionIndex + 1}`;
questionText.textContent = currentQuestion.question;

//Clear and populate answers
answersContainer.innerHTML = "";
currentQuestion.options.forEach((option, index) => {
const label = document.createElement("label");
label.className = "d-block";
const input = document.createElement("input");
input.type = "radio";
input.name = "answer";
input.value = index;

// Pre-check if already answered
if (currentQuestion.answer === index.toString()) {
input.checked = true;
}

label.appendChild(input);
label.append(option);
answersContainer.appendChild(label);
});


// Update progress bar
progressBar.style.width = `${((currentQuestionIndex + 1) / questions.length) * 100}%`;
prevBtn.disabled = currentQuestionIndex === 0;
nextBtn.textContent = currentQuestionIndex === questions.length - 1 ? "Submit" : "Next";

// Add event listeners to options
document.querySelectorAll("input[type='radio']").forEach(radio => {
radio.addEventListener("change", handleNextQuestion);
});
}


Step 4: Handling Navigation:

handleNextQuestion manages answer submission and moves to the next question. It also validates answers and calculates the score.

function handleNextQuestion() {
setTimeout(() => {
const selectedAnswer = document.querySelector("input[name='answer']:checked");
if (!selectedAnswer) {
alert("Please select an answer.");
return;
}

questions[currentQuestionIndex].answer = selectedAnswer.value;

// Check correctness
if (parseInt(selectedAnswer.value) === questions[currentQuestionIndex].correctAnswer) {
questions[currentQuestionIndex].correct = true;
correctAnswersCount++;
} else {
questions[currentQuestionIndex].correct = false;
}

// Save progress in localStorage
localStorage.setItem("questions", JSON.stringify(questions));

if (currentQuestionIndex < questions.length - 1) {
currentQuestionIndex++;
updateQuestion();
} else {
showResults();
}

}, 500); // Delay for smooth UI transition
}

Step 5: Displaying Results

The showResults function hides the quiz and displays a summary of correct and incorrect answers, grouped by category.

function showResults() {

questionSection.style.display = "none";
resultsSection.style.display = "block";

const categories = [...new Set(questions.map(item => item.category))];
let index = 0;

categories.forEach(category => {
const categoryQuestions = questions.filter(item => item.category === category);

categoryQuestions.forEach((question) => {
const questionDiv = document.createElement("div");
questionDiv.className = "question";
questionDiv.innerHTML = `
<h3>
${question.options[question.correctAnswer] === question.options[question.answer] ? "✅" : "❌"}
Question ${index + 1}
</h3>
<p>${question.question}</p>
<ul>
<li>Correct Answer: ${question.options[question.correctAnswer]}</li>
<li>Your Answer: ${question.options[question.answer]}</li>
</ul>
`;
resultsSection.appendChild(questionDiv);
index++;
});
});

document.getElementById("correctAnswers").textContent = correctAnswersCount;
}

That's the primary functionality. You can view all the code and the question set.

👀 View the quiz code
View the questions JSON

Take it, improve it, and create your own quizzes. If you do, let us know!

Happy coding!

🤙 the Slater Team

📚 Buy the physical book

🖨️ Check out Wes

If Slater helps you create better websites, please support the team behind it.

Welcome To Slater!

Slater resources, updates and community activity

Read more from Welcome To Slater!

The team behind Slater would like to wish you a Merry Christmas and a happy New Year! 🎄🎅🎁 Get the Santa ASCII art: https://slater.app/projects/11431/pages/27608 Happy coding! 🤙 the Slater Team If Slater helps you create better websites, please support the team behind it. Become a Pro Slater User

Earlier this year, we built figdam.com. It is currently used by several of our clients to host files and watermark PDFs. We’d like to bring this file hosting functionality to Slater users. With that in mind, where do you currently store files that Webflow doesn’t support? Would this feature be useful to you? What file hosting features do you need? Let us know. JS 101: File types File storage? Javascript? Let's consider all of the different file types that you could host and then retrieve and...

Hi, Just a reminder that Kendra and Mason will be hosting an EA Office Hours Zoom this Friday, the 13th (spooky…) to chat about topics relating to Chapter 1: Sales for Creative Types. Sign up if you can make it, and bring your questions. Let’s get past any lingering sales ick together. Register to join us this Friday, 12/13 here. Also, if you can’t make it this week, we’re thinking about doing it again next Friday, 12/20 as well, if anyone is game? To ring in the holiday break, we’ll chat...