Build an Interactive Quiz using ⚡AMP Email
Tags: email, ampforemail, html, css
Published: 2024-03-25 04:00:21

## Background
Many news organizations create [weekly quizzes](https://www.nytimes.com/spotlight/news-quiz) about recent events. These organizations usually send out an email containing a link to the quiz hosted on their website. This requires users to click on the link and navigate to a landing page to play the quiz.

## The Goal
***Instead of leaving the inbox to play the quiz in a web browser, is it possible to create a fully playable quiz within the email?*** Yes, through the use of AMP email and the `amp-bind` component, you can build an interactive quiz.

## 🛠️ Let's Start Building
The following is a step by step guide for building a short, four question AMP quiz. Scroll to the bottom to view the AMP quiz demo ⏬

---

## 🏗️ AMP Boilerplate Template

1). Start by setting up an [AMP email template](https://amp.dev/documentation/guides-and-tutorials/email/start/create_email?redirected#start-with-the-amp-email-boilerplate) with the required `amp-bind` [script](https://amp.dev/documentation/components/email/amp-bind) in the `<head>` tag

Below is a sample AMP email boilerplate:

```html
<!doctype html>
<html ⚡4email data-css-strict lang="en">
<head>
  <meta charset="utf-8">
  <script async src="https://cdn.ampproject.org/v0.js"></script>
  <script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>
  <style amp4email-boilerplate>body{visibility:hidden}</style>
  <style amp-custom>
    h1 {
      margin: 1rem;
    }
  </style>
</head>
<body>
  <h1>Hello, I am an AMP EMAIL!</h1>
</body>
</html>
```

## ❓ Question ✅ Answer Modules

2). Create the first quiz question and corresponding choices

```html
<h3>Question #1</h3>
<h2>How many boroughs make up New York City?</h2>
<article id="q1Question">
  <button>
    Four
  </button>
  <button>
    Five
  </button>
  <button>
    Six
  </button>
  <button>
    Seven
  </button>
</article>
```

![First question with corresponding choices](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f3fpbkylpsuxa5pglot0.png)

3). Then create the answer module below the original choices. This module will reveal the player's correct or incorrect answer selection

```html
<h3>Question #1</h3>
<h2>How many boroughs make up New York City?</h2>
<article id="q1Question">
  <button>
    Four
  </button>
  <button>
    Five
  </button>
  <button>
    Six
  </button>
  <button>
    Seven
  </button>
</article>
<article id="q1Answer">
  <button>
    Four
  </button>
  <button>
    Five
  </button>
  <button>
    Six
  </button>
  <button>
    Seven
  </button>
</article>
```

4). Apply the `hidden` attribute to hide the quiz answer module

```html
<article id="q1Answer" hidden>
...
</article>
```

In order to hide the question module and reveal the answer module after selecting a choice, we need to create an event handler that listens to this action.

5). Use the `on` attribute to create an [event handler](https://amp.dev/documentation/guides-and-tutorials/email/learn/amp-email-actions-and-events) that hides the question module and reveals the answer module after "tapping" on one of the choices

```html
<h3>Question #1</h3>
<h2>How many boroughs make up New York City?</h2>
<article id="q1Question">
  <button on="tap:q1Question.hide,q1Answer.show">
    Four
  </button>
  <button on="tap:q1Question.hide,q1Answer.show">
    Five
  </button>
  <button on="tap:q1Question.hide,q1Answer.show">
    Six
  </button>
  <button on="tap:q1Question.hide,q1Answer.show">
    Seven
  </button>
</article>
```

The purpose of this event handler is to prevent users from answering the question again after making an initial selection.

Now let's reveal the correct answer and indicate through CSS styling and classes whether the selected option was correct or incorrect ⬇️

6). Use [`AMP.setState()`](https://amp.dev/documentation/components/email/amp-bind#defining-and-initializing-state-with-%3Camp-state%3E) to bind a `correct` or `incorrect` class to each of the options

```html
<h3>Question #1</h3>
<h2>How many boroughs make up New York City?</h2>
<article id="q1Question">
  <button on="tap:q1Question.hide,q1Answer.show,AMP.setState({btn2Class: 'correct', btn1Class: 'incorrect'})">
    Four
  </button>
  <button on="tap:q1Question.hide,q1Answer.show,AMP.setState({btn2Class: 'correct'})">
    Five
  </button>
  <button on="tap:q1Question.hide,q1Answer.show,AMP.setState({btn2Class: 'correct', btn3Class: 'incorrect'})">
    Six
  </button>
  <button on="tap:q1Question.hide,q1Answer.show,AMP.setState({btn2Class: 'correct', btn4Class: 'incorrect'})">
    Seven
  </button>
</article>
```

7). Add the corresponding `[class]` attribute to each of the options in the answer module

```html
<h3>Question #1</h3>
<h2>How many boroughs make up New York City?</h2>
<article id="q1Question">
  <button on="tap:q1Question.hide,q1Answer.show,AMP.setState({btn2Class: 'correct', btn1Class: 'incorrect'})">
    Four
  </button>
  <button on="tap:q1Question.hide,q1Answer.show,AMP.setState({btn2Class: 'correct'})">
    Five
  </button>
  <button on="tap:q1Question.hide,q1Answer.show,AMP.setState({btn2Class: 'correct', btn3Class: 'incorrect'})">
    Six
  </button>
  <button on="tap:q1Question.hide,q1Answer.show,AMP.setState({btn2Class: 'correct', btn4Class: 'incorrect'})">
    Seven
  </button>
</article>
<article id="q1Answer" hidden>
  <button [class]="btn1Class || ''">
    Four
  </button>
  <button [class]="btn2Class || ''">
    Five
  </button>
  <button [class]="btn3Class || ''">
    Six
  </button>
  <button [class]="btn4Class || ''">
    Seven
  </button>
</article>
```

The `AMP.setState({btn2Class: 'correct', btn1Class: 'incorrect'})` action will assign the `correct` CSS class through the `[class]="btn2Class || ''"` expression. It will also assign the `incorrect` CSS class through the `[class]="btn1Class || ''"` expression. The same logic applies to the rest of the buttons.

8). Create the `correct` and `incorrect` classes and add the CSS styling

```css
/* AMP.setState CLASSES */
.correct {
  background-color: #3beb57;
  color: #000000;
}
.incorrect {
  background-color: #ff3636;
  color: #ffffff;
}
```

Up to this point, we have created the first quiz question with four different options. When a user selects one of the options, the hidden answer module will reveal and the `correct` and `incorrect` class expression will render.

![AMP quiz question #1 demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0kejcadh2yn7iij81emv.gif)

## 💯 Recording the Quiz Score

Now let's use `amp-bind` to track a user's quiz score as they answer each question.

9). Use the `AMP.setState()` action and the `[text]` attribute to record and display a score. The state variable `quizScore` will now update to the value of `1` if the correct option is selected or `0` for the incorrect options

```html
<h3>Question #1</h3>
<h3>Your Score: <span [text]="quizScore">0</span></h3>
<h2>How many boroughs make up New York City?</h2>
<article id="q1Question">
  <button on="tap:q1Question.hide,q1Answer.show,AMP.setState({btn2Class: 'correct', btn1Class: 'incorrect', quizScore: 0})">
    Four
  </button>
  <button on="tap:q1Question.hide,q1Answer.show,AMP.setState({btn2Class: 'correct', quizScore: 1})">
    Five
  </button>
  <button on="tap:q1Question.hide,q1Answer.show,AMP.setState({btn2Class: 'correct', btn3Class: 'incorrect', quizScore: 0})">
    Six
  </button>
  <button on="tap:q1Question.hide,q1Answer.show,AMP.setState({btn2Class: 'correct', btn4Class: 'incorrect', quizScore: 0})">
    Seven
  </button>
</article>
```

![AMP score change demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ui684mkkx927kwvmrbsf.gif)

## ⏩ Next Quiz Question

After a quiz question is answered, let's provide a way to move onto the next question.

10). Create a "Next question" button within the hidden answer module

```html
<article id="q1Answer" hidden>
  <button [class]="btn1Class || ''">
    Four
  </button>
  <button [class]="btn2Class || ''">
    Five
  </button>
  <button [class]="btn3Class || ''">
    Six
  </button>
  <button [class]="btn4Class || ''">
    Seven
  </button>
  <button on="tap:q1Section.hide,q2Section.show">
    Next question &#x2192;
  </button>
</article>
```

11). Then wrap the entire question #1 module (including the question and answer modules) in a `<section>` element. Wrap the entire question #2 module using the same method

```html
<!-- QUESTION #1 -->
<section id="q1Section">
  <h3>Question #1</h3>
  <h2>How many boroughs make up New York City?</h2>
  ...
</section>
<!-- end question #1 -->

<!-- QUESTION #2 -->
<section id="q2Section" hidden>
  <h3>Question #2</h3>
  <h2>What is the largest park in NYC?</h2>
  ...
</section>
<!-- end question #2 -->
```

The "Next question" button with the `on="tap:q1Section.hide,q2Section.show"` event will hide question #1 and display question #2.

![Next question demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3osrkyuxajfcb5t7kayh.gif)

Repeat these steps for questions #2 and #3 to finish building the quiz. Now the quiz is completed 🙌

---

## 🕹️ AMP Quiz Demo
Below is a demo featuring a four question quiz with some added CSS styling.

> ⚠️ ***NOTE: Copy & paste the HTML tab code into the [Gmail AMP Playground](https://amp.gmail.dev/playground/) or the [amp.dev Playground](https://playground.amp.dev/?mode=Responsive&runtime=amp4email#) for a more accurate demo experience!***

{% codepen https://codepen.io/bdjang/pen/ZEZpxMx %}

---

## 🤔 Can We Automate?
Once this AMP email quiz template is created, can weekly email sends be automated with new questions pulling in from a [CORS JSON endpoint](https://amp.dev/documentation/guides-and-tutorials/email/learn/cors-in-email)?

It is possible to pull in the text content (i.e. quiz questions and options to choose from), however, ***the logic determining which option is correct and which options are incorrect are built into the `on` attribute and event handler***. 

**In other words, the position of the "correct" options will always stay the same for each question due to the inline nature of the AMP logic - only the text content will change**. This is not an ideal situation because users will eventually learn where the "correct" option is located regardless of the quiz question content.

Currently, the only option with this particular AMP template is to *manually shuffle* the `<button>` elements to randomize the "correct" option 🙃.

![Manually randomize options](https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExYnd2YndmMjF5dXZ5bzk2bzRzcHU5dDA0NWQ1MWZibmh5Z3lpNHMxOSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/3o6MbsNCPeLXgcNWDK/giphy.gif)

---

## Conclusion
A fully interactive quiz can be built entirely inside of an email by using the `amp-bind` component. Individual scores can also be tracked based on the user selections.

Although there is no straightforward solution for automating this AMP quiz template, the fact that users can complete the quiz without leaving their inbox is a <u>**clear win**</u> 🏆.