Courses/Streamlit: 20 Real Apps/Module 3: Beginner Projects
Module 3 · Lesson 630 minBeginner

Project 6: Interactive Quiz App

What you'll build
Build a scored quiz — your first app that behaves like a state machine.

Introduction

This project guides you through building an Interactive Quiz App using Python and Streamlit. The app presents multiple-choice questions one at a time, tracks the user's score with st.session_state, and gives instant feedback after every answer. If you like data-driven apps, this quiz pairs naturally with the Pandas dashboard tutorial.

Prerequisites

  • Python 3.8+python.org
  • Streamlit:
  • code
    pip install streamlit

    Step 1: Create the Script

    Create quiz_app.py and paste the following:

    code
    import streamlit as st
    
    st.set_page_config(page_title="Quiz App", page_icon="🧠")
    st.title("🧠 Interactive Quiz App")
    
    QUESTIONS = [
        {
            "question": "What is the capital of France?",
            "options": ["Berlin", "Madrid", "Paris", "Rome"],
            "answer": "Paris",
        },
        {
            "question": "Which planet is known as the Red Planet?",
            "options": ["Earth", "Mars", "Jupiter", "Venus"],
            "answer": "Mars",
        },
        {
            "question": "What is the highest mountain in the world?",
            "options": ["K2", "Kangchenjunga", "Mount Everest", "Lhotse"],
            "answer": "Mount Everest",
        },
        {
            "question": "How many sides does a hexagon have?",
            "options": ["5", "6", "7", "8"],
            "answer": "6",
        },
        {
            "question": "Which language is primarily used for web styling?",
            "options": ["Python", "JavaScript", "CSS", "SQL"],
            "answer": "CSS",
        },
    ]
    
    for key, default in [("score", 0), ("current", 0), ("finished", False)]:
        if key not in st.session_state:
            st.session_state[key] = default
    
    if st.session_state.finished:
        total = len(QUESTIONS)
        score = st.session_state.score
        st.balloons()
        st.subheader("🎉 Quiz Complete!")
        st.metric("Your Score", f"{score} / {total}")
        pct = score / total * 100
        if pct >= 80:
            st.success("Excellent work! 🌟")
        elif pct >= 60:
            st.info("Good job! Keep practising. 📚")
        else:
            st.warning("Keep trying — you will get there! 💪")
        if st.button("🔄 Restart Quiz"):
            st.session_state.update({"score": 0, "current": 0, "finished": False})
            st.rerun()
    else:
        idx = st.session_state.current
        q = QUESTIONS[idx]
        st.progress(idx / len(QUESTIONS), text=f"Question {idx + 1} of {len(QUESTIONS)}")
        st.subheader(q["question"])
        selected = st.radio("Choose your answer:", q["options"], key=f"q_{idx}")
        if st.button("Submit Answer"):
            if selected == q["answer"]:
                st.success("✅ Correct!")
                st.session_state.score += 1
            else:
                st.error(f"❌ Wrong! The correct answer was **{q['answer']}**.")
            st.session_state.current += 1
            if st.session_state.current >= len(QUESTIONS):
                st.session_state.finished = True
            st.rerun()

    Step 2: Run the App

    code
    streamlit run quiz_app.py

    Step 3: Use the App

    The quiz shows one question at a time with a progress bar at the top. Select an answer and click Submit Answer to get instant feedback. After the final question the score screen appears with a performance message.

    How It Works

    The quiz is a state machine: questions live in a Python list of dicts, and st.session_state["q_num"] tracks where the user is. Each rerun renders the current question with st.radio, and the Submit button checks the answer, stores the result, and increments the counter — triggering a rerun that shows the next question.

    Because Streamlit re-executes the whole script per interaction, all progress *must* live in st.session_state; anything stored in a plain variable evaporates on rerun. That single concept — session state as the app's memory — is the core lesson of this project.

    At the end, results render as a score plus st.balloons(). With a few more lines the answers list becomes a DataFrame and you get per-question analytics with st.bar_chart, exactly the technique from the data dashboard.

    Key Concepts

  • `st.session_state` — Persists the score and current question index across app reruns.
  • `st.radio()` — Renders the multiple-choice options as radio buttons.
  • `st.progress()` — Displays a progress bar showing how far through the quiz the user is.
  • `st.rerun()` — Re-runs the script to advance to the next question instantly.
  • `st.balloons()` — Plays a fun balloon animation on the results screen.
  • What to Try Next

  • Load questions from a JSON file so you can add new ones without editing code.
  • Add a countdown timer for each question using time.time().
  • Show a brief explanation for each answer after the user submits.
  • Save high scores to a CSV file and display a leaderboard with pandas.
  • Common Errors & Fixes

  • Quiz restarts on every answer — the question index is a local variable instead of st.session_state.
  • Double-submit counts twice — the button check runs before the state increments; use the on_click callback form or guard with if st.button(...) and not answered.
  • `KeyError: 'q_num'` — session keys must be initialized before first read: st.session_state.setdefault("q_num", 0).
  • Radio shows previous selection — give the radio a key and reset it when advancing questions.
  • FAQ

    How do I load questions from a file?

    Read a JSON/CSV into the questions list at startup — the structure matches the blog content files pattern: one object per question.

    Can I add a timer per question?

    Yes — record time.time() when the question renders and compare on submit; Streamlit's st_autorefresh component can force the check.

    How do I show a results breakdown?

    Convert the results list to a DataFrame and use st.bar_chart(df) — five lines, covered in the dashboard tutorial.

    Adapted from: Interactive Quiz App using Python and Streamlit

    Checkpoint
    Questions advance, answers score, and the results screen shows your total.
    What you learned
    • Session state as a state machine
    • Guarded button logic
    • Rendering results with charts