Create an email with multiple pages

This interactive AMP email demonstrates how you can guide users through a step-by-step process using page navigation and AMP state logic—all within an email. No backend or styles required. You can expand on this format for onboarding flows, tutorials, or gated CTA experiences.

Step 1: Basic AMP Email Setup

We’ll begin with a clean AMP email shell. This sets up the document type, AMP boilerplate, and includes the amp-bind and amp-form scripts that we’ll use later. The CSS will stay minimal for now—just enough to help us orient ourselves visually.

Here’s what our starting structure looks like:

<!doctype html>
<html ⚡4email data-css-strict>
	<head>
	<meta charset="utf-8">
	<style amp4email-boilerplate>body{visibility:hidden}</style>
	<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 amp-custom>
				/* Styles will go here */
		</style>
	</head>
<body>
	<div class="container">
		<div class="content-box">
			<section class="pages">
				<!-- All Pages will go here -->
			</section>
		</div>
	</div>
	<footer style=""> <!-- Static footer -->
		<a href="https://gregheindel.me">gregheindel.me</a>
	</footer>
</body>
</html>
								

In the next step, we’ll start adding content for the first two pages of our interactive experience.

Step 2: Create Pages 1 and 2

Before we get into AMP logic, we’ll lay out the structure for Page 1 and Page 2 of the experience. Each page will live inside its own div so we can later toggle visibility using AMP bindings. For now, everything will render together so we can visually confirm our structure.

Page 1 introduces the checklist. Page 2 lists technical requirements. This is a good point to reinforce how AMP emails can include multi-part experiences without needing additional screens.

Add the following inside the .container div:

<div id="Page_1">
	<div class="inner-content-box">
		<div class="center">
			<amp-img 
				aria-describedby=""
				src="https://gregheindel.me/img/email/search.png"
				width="128" 
				height="128">
			</amp-img>
		</div>
		<div class="center">
			<h1 class="center">How to get approved to send AMP Emails</h1>
			<p> 
				If you want to send AMP emails in production, you need to be approved by Google and configure a few technical and structural requirements. This guide will walk you through each step in a lightweight interactive format. 
			</p>
			<div class="center">
				<button 
					type="button" 
					class="btn btn-red"
				>
					Get Started
				</button>
			</div>
		</div>
	</div>
</div>
<div id="Page_2">
	<div class="inner-content-box">
		<h1>
			Technical Requirements
		</h1>
		<p>Before applying for AMP email approval, your domain and email setup need to meet certain technical standards. These ensure your messages are secure and reliably delivered.</p>
		<div class="checkboxes">
			<label><input type="checkbox" name="domain_verified"> My sending domain is <a href="https://gmail.com/postmaster/">verified in Google Postmaster Tools</a></label><br>
			<label><input type="checkbox" name="dkim_setup"> Domain has SPF, DKIM, and DMARC properly configured</label><br>
			<label><input type="checkbox" name="https_images"> All my image and hyperlink URLs use HTTPS</label><br>
			<label><input type="checkbox" name="plain_fallback"> My AMP email includes a plain text and HTML <a href="https://amp.dev/documentation/guides-and-tutorials/learn/email-spec/amp-email-structure">MIME fallback</a></label>
		</div>
		<div class="center">
			<button 
				type="button" 
				class="btn btn-next" 
			>
				NEXT
			</button>
		</div>
	</div>
</div>
								

You should now see both pages rendered in the email. In the next step, we’ll apply logic to show one page at a time using amp-bind. This is where the magic begins.

Step 3: Add amp-state Logic to Toggle Pages

Now that we’ve built our static structure, let’s make it interactive. The goal is to show only one “page” at a time and allow users to navigate between them using buttons.

To do that, we’ll introduce amp-bind, AMP’s simple way of managing state (like variables). We’ll create a state variable called step, and conditionally show or hide each page depending on its value.

What We're Doing (and Why)

  • We'll define a starting state with amp-state id="step".
  • Then we'll bind the [hidden] attribute to each page’s step value.
  • We'll use buttons to change the step value and navigate forward or back.
Add the State Definition

Place this line directly inside the <body> tag, before your .container:

<amp-state id="step">
<script type="application/json"></script>
</amp-state>

This sets our initial view to Page 1.

Update Your Pages With [hidden] Logic

Update each div which contains the page id with logic that hides or shows based on the value of step.

Page 1:
<div [hidden]="step != 1" id="Page_1"> <!-- Here -->
	<div class="center">
	  <h1>How to get approved to send AMP Emails</h1>
	  <p>If you want to send AMP emails in production, you need to be approved by Google and configure a few technical and structural requirements. This guide walks you through each step in a lightweight, interactive format.</p>
	  <button class="btn btn-red" on="tap:AMP.setState({ step: 2 })">Get Started</button> <!-- Here -->
  </div>
</div>

Page 2:
<div hidden [hidden]="step != 2" id="Page_2"> <!-- Here -->
	<div class="inner-content-box">
		<h1>
			Technical Requirements
		</h1>
		<p>Before applying for AMP email approval, your domain and email setup need to meet certain technical standards. These ensure your messages are secure and reliably delivered.</p>
		<div class="checkboxes">
			<label><input type="checkbox" name="domain_verified"> My sending domain is <a href="https://gmail.com/postmaster/">verified in Google Postmaster Tools</a></label><br>
			<label><input type="checkbox" name="dkim_setup"> Domain has SPF, DKIM, and DMARC properly configured</label><br>
			<label><input type="checkbox" name="https_images"> All my image and hyperlink URLs use HTTPS</label><br>
			<label><input type="checkbox" name="plain_fallback"> My AMP email includes a plain text and HTML <a href="https://amp.dev/documentation/guides-and-tutorials/learn/email-spec/amp-email-structure">MIME fallback</a></label>
		</div>
		<div class="center">
			<button 
				type="button" 
				class="btn btn-next" 
				on="tap:AMP.setState({ step: 3 })"> <!-- Here -->
					NEXT
			</button>
		</div>
	</div>
</div>

💡 Pro Tip: The [hidden]="step != 1" syntax hides the element unless step equals 1. This way, we control page visibility through AMP state.

You're now officially controlling your AMP email's view state with a lightweight, client-side state machine!

Step 4: Add Pages 3 and 4

Next, we’ll complete the sequence by adding two more pages and updating our logic to support navigation through the full flow. These pages cover development requirements and provide a final congratulatory screen with links to submit for AMP approval.

Add the following inside the .container after Page 2:

<div hidden [hidden]="step !=3">
	<div class="inner-content-box">
		<h1>Email Development Requirements</h1>
		<p>In addition to backend setup, Google expects AMP emails to follow a clean and well-structured development approach. This ensures the messages render correctly and provide a high-quality experience.</p>
		<div class="checkboxes">
			<label><input type="checkbox" name="amp_validated"> I have validated my AMP email in the <a href="https://playground.amp.dev/"> AMP Playground</a></label><br>
			<label><input type="checkbox" name="no_inline_scripts"> The email contains no inline JavaScript or disallowed tags</label><br>
			<label><input type="checkbox" name="amp_ready"> The AMP version of the email is production ready</label><br>
		</div>
		<div class="center">
			<button type="button" 
				class="btn btn-back" 
				on="tap:AMP.setState({step:2})">
				GO BACK
			</button>
			<button 
				type="button" 
				class="btn btn-next" 
				on="tap:AMP.setState({step:4})">
				NEXT
			</button>
		</div>
	</div>
</div>
<!--  PAGE 4 -->
<div hidden [hidden]="step !=4" class="center">
	<div class="inner-content-box">
		<div>
			<div class="center">
				<amp-img 
					class="circle-img"
					aria-describedby=""
					src="https://gregheindel.me/img/email/reward.png"
					width="128" 
					height="120">
				</amp-img>
			</div>
			<h1>
				Congratulations!
			</h1>
			<p>
				Nice! Once you're ready to submit, send your production ready AMP Email to <b>ampforemail.whitelisting@gmail.com</b> and then apply for approval using <a href="https://developers.google.com/workspace/gmail/ampemail/register">Google's AMP Email registration form</a>.
			</p>
		</div>
		<div class="center">
			<button type="button" 
				class="btn btn-back" 
				on="tap:AMP.setState({step:3})">
				GO BACK
			</button>
			<button 
				type="button" 
				class="btn btn-red" 
				on="tap:AMP.setState({step:1})">FROM THE TOP
			</button>
		</div>
	</div>
</div>

You now have a complete interactive AMP email experience using only AMP HTML, amp-state, and amp-bind. In the next step, we’ll explore ways to style and polish the final output.

Final Touches: Styling

If you read my guide discussing the flexibility of CSS within AMP Emails then you know we can confidently apply it to our email. Now that the experience is functional, let’s add the complete polished styles we used in the live demo. Paste the following inside your style amp-custom block

body {
	font-family: 'Montserrat', sans-serif;line-height:20pt;
	margin:0;
	background-color: #FDFBEE;
}
.checkboxes {margin:30px auto;}
.container {
	border-radius: 15px;
	padding: 0px 0px 25px 0px;
	margin: 0px auto;
	max-width: 100%;
	background-color: #FDFBEE;
}
.inner-content-box {
	max-width: 600px;
	margin:0 auto;
	padding:0 0 20px 0;
}
.btn {
	border-radius: 3px;
	text-align: center;
	padding: 15px 22px;
	border: none;
	line-height: 22px;
	font-size: 18px;
	font-weight: bold;
	max-width: 300px;
	display:inline-block;
}
.btn-red {
	background: #FE4F2D ;
	color: #FDFBEE;
	border:1px solid #fefefe;
}
.btn-next {
	background: #063f66 ;
	color: #fff;
	border:1px solid #fefefe;
}
.btn-back {
	background: #fefefe;
	color: #666;
	border:1px solid #eee;
}
.btn:hover {cursor: pointer;box-shadow: 3px 3px 3px rgba(0,0,0,.2);transition-duration: .5s;}
.center {text-align: center;}
.pages {padding: 0 15px;}
.circle-img {border-radius: 50px;}
a{color:#FE4F2D;}
label{
	font-size:1.2rem ;
	color:#666;
}
h1 {color:#40a4db;font-size:2rem;line-height:1;}
h3 {color:#063f66 ;font-size:1.5rem;line-height:1;margin:0px 0 35px 0;}
p {color:#666;font-size: 1.2rem;}
.content-box {
	text-align: left;
	padding: 0px 0px 15px 0px;
	max-width: 850px;
	margin: 0px auto;
}
footer{
	color: #999;
	font-family: Open Sans, Helvetica Neue, Helvetica, Arial, sans-serif;
	font-size: 12px;
	line-height: 150%;
	text-align: justify;
	text-align: center;
	background: #FDFBEE;
}
footer > a {color:#40a4db;}

🚀 That's it!

Congratulations — Now you can create multi-page email with AMP! Try implementing this same logic into a navbar for a website style navigation or to hide and reveal smaller elements like a button when another element is clicked. There are many applications for using amp-bind this way. Got an idea? Share it with me!

If you are having trouble getting the AMP Email to render properly, you can download the full file here.

Be the first to know when I publish exclusive content by subscribing to my newsletter!

Next Topics

  • How display dynamic content in real-time
  • Create a real working mortgage calculator
This site uses cookies 🍪. You can't eat them but if you click "Accept" this awful banner will go away. Learn More.