DEV Community

Cover image for Build an Interactive Quiz using ⚡AMP Email
benjamin
benjamin

Posted on • Edited on

Build an Interactive Quiz using ⚡AMP Email

Background

Many news organizations create weekly quizzes 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 with the required amp-bind script in the <head> tag

Below is a sample AMP email boilerplate:



<!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>


Enter fullscreen mode Exit fullscreen mode

❓ Question ✅ Answer Modules

2). Create the first quiz question and corresponding choices



<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>


Enter fullscreen mode Exit fullscreen mode

First question with corresponding choices

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



<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>


Enter fullscreen mode Exit fullscreen mode

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



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


Enter fullscreen mode Exit fullscreen mode

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 that hides the question module and reveals the answer module after "tapping" on one of the choices



<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>


Enter fullscreen mode Exit fullscreen mode

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() to bind a correct or incorrect class to each of the options



<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>


Enter fullscreen mode Exit fullscreen mode

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



<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>


Enter fullscreen mode Exit fullscreen mode

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



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


Enter fullscreen mode Exit fullscreen mode

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

💯 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



<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>


Enter fullscreen mode Exit fullscreen mode

AMP score change demo

⏩ 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



<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>


Enter fullscreen mode Exit fullscreen mode

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



<!-- 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 -->


Enter fullscreen mode Exit fullscreen mode

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

Next question demo

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 or the amp.dev Playground for a more accurate demo experience!


🤔 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?

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


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 clear win 🏆.

Top comments (0)