1 of 57

Building Interactive Sites with AMP

2 of 57

Mashhood Rastgar

Leads the Engineering Team at �Sastaticket.pk. Google Developer Expert for Web and Angular.

@mashhoodr

3 of 57

News and blogs

4 of 57

E-commerce

sites

5 of 57

6 of 57

Actions and events

7 of 57

8 of 57

click

mousedown

mouseup

touchstart

touchend

9 of 57

10 of 57

11 of 57

<div id="warning">This is a warning.</div>

<button onclick="document.getElementById('warning').hidden = true;">

Hide Warning

</button>

<div id="warning">This is a warning.</div>

<button onclick="$('#warning').hide();">

Hide Warning

</button>

<div id="warning">This is a warning.</div>

<button on="tap:warning.hide">

Hide Warning

</button>

12 of 57

13 of 57

Our menu

<amp-sidebar id="sidebar" layout="nodisplay" side="right">

<div class="menu-header">

<div role="button" on="tap:sidebar.toggle" tabindex="0"></div>

</div>

<ul class="label">

<li><a href="/product-listing?gender=women">Women</a></li>

<li><a href="/product-listing?gender=men">Men</a></li>

<li><a href="/contact.html">Contact us</a></li>

</ul>

</amp-sidebar>

<div role="button" on="tap:sidebar.toggle" tabindex="0"></div>

14 of 57

Composing components

15 of 57

<amp-script>

16 of 57

17 of 57

18 of 57

Menu with submenu

<amp-sidebar id="sidebar1" layout="nodisplay" side="right">

<ul>

<li>Menu item 1<li>

<li>Menu item with submenu!</li>

<amp-accordion layout="container">

<section>

<header>Expand me</header>

<ul>

<li>Submenus are great</li>

<li>Everyone loves them</li>

</ul>

</section>

</amp-accordion>

</li>

</ul>

</amp-sidebar>

19 of 57

20 of 57

Double carousel

<amp-selector id="selector" layout="container"

on="select:carousel.goToSlide(index=event.targetOption)">

<amp-img option="0" selected src="image0.jpg" width="60" height="40"></amp-img>

<amp-img option="1" src="image1.jpg" width="60" height="40"></amp-img>

<amp-img option="2" src="image2.jpg" width="60" height="40"></amp-img>

<amp-img option="3" src="image3.jpg" width="60" height="40"></amp-img>

</amp-selector>

<amp-carousel id="carousel" width="400" height="300" layout="responsive" type="slides"

on="slideChange:selector.toggle(index=event.index, value=true)">

<amp-img src="image0_large.jpg" layout="fill"></amp-img>

<amp-img src="image1_large.jpg" layout="fill"></amp-img>

<amp-img src="image2_large.jpg" layout="fill"></amp-img>

<amp-img src="image3_large.jpg" layout="fill"></amp-img>

</amp-carousel>

21 of 57

Server calls

22 of 57

23 of 57

<amp-form>

24 of 57

<form method="post" action-xhr="/submit-form" target="_top">

<div class="input">

<input type="text" name="name" id="form-name" required>

<label for="form-name">Name:</label>

</div>

<div class="input">

<input type="email" name="email" id="form-email" required>

<label for="form-email">Email:</label>

</div>

<input type="submit" value="Subscribe" class="btn">

<div submit-success>

<template type="amp-mustache">

<p class="form-submit-response">

Success! Thanks {{name}} for subscribing!

</p>

</template>

</div>

<div submit-error>

<template type="amp-mustache">

<p class="form-submit-response">

Oops! Sorry, there was an error.

</p>

</template>

</div>

</form>

25 of 57

26 of 57

<form id="form-cart-delete"

method="POST"

action-xhr="/api/delete-cart-item"

on="submit-success: AMP.setState({cartItemsList: event.response})">

<input type="hidden" name="productId" value=""

[value]="itemToRemove.productId">

<input type="hidden" name="color" value=""

[value]="itemToRemove.color">

<input type="hidden" name="size" value=""

[value]="itemToRemove.size">

</form>

<amp-form>

27 of 57

blank

28 of 57

<amp-list>

amp-mustache

29 of 57

<amp-list id="cart-count" src="/api/cart-count" height="17" width="17">

<template type="amp-mustache">

{{#count}}

<span>{{count}}</span>

{{/count}}

</template>

</amp-list>

{"items":[{"count":1}]}

<amp-list> & amp-mustache

30 of 57

Get fresh price and availability with <amp-list>

31 of 57

<amp-list>

<amp-list>

...

32 of 57

XHR Batching

<amp-list>

<amp-list>

33 of 57

State and binding

34 of 57

35 of 57

var itemToRemove = 123;

36 of 57

<amp-state id="itemToRemove">

<script type="application/json">

{

"productId": 123,

"color": "red",

"size": "L"

}

</script>

</amp-state>

Application state variable

37 of 57

<div role="button" class="cart-remove-icon" tabindex="0"

on="tap: AMP.setState({

itemToRemove: {

productId: 123,

size: 'red',

color: 'L'

}}), form-cart-delete.submit">

</div>

Application state variable

38 of 57

<amp-bind>

State.

Bind.

Mutate.

39 of 57

<amp-state id="team">

<script type="application/json">

{ "star": "Yao Ming" }

</script>

</amp-state>

<p [text]="team.star + ' is tall!'">

Yao Ming is tall!

</p>

<button on="tap:AMP.setState({team: {star: '姚明'}})">

What's his real name?

</button>

40 of 57

Sort and

filter:

<amp-list>

+

<amp-bind>

41 of 57

STATE

<amp-state id="products">

<script type="application/json">

{

"gender": "<%productsGender%>",

"category": "<%productsCategory%>",

"filter": "high-low"

}

</script>

</amp-state>

42 of 57

BIND

<select name="price" id="price"

on="change: AMP.setState({products: {filter: event.value}})">

<option value="high-low">Price: High-Low</option>

<option value="low-high">Price: Low-High</option>

</select>

43 of 57

MUTATE

<amp-list id="products-list"

[src]="'/api/categories?categoryId=' + products.gender + '-' +

products.category + '&sort=' + products.filter"

src="/api/categories?categoryId=<%productsGender%>-<%productsCategory%>&sort=high-low"

height="1000"

width="300"

layout="responsive">

</amp-list>

/api/categories?categoryId=men-shirts&sort=high-low

/api/categories?categoryId=women-shorts&sort=low-high

...

44 of 57

Remove cart item

<amp-list>

+

<amp-bind>

+

<amp-form>

45 of 57

<amp-list> builds cart

<amp-list src="/cart_items" [src]="cartItemsList.items">

. . .

<template type="amp-mustache">

. . .

<div role="button" class="cart-remove-icon" tabindex="0"

on="tap: AMP.setState({

itemToRemove: {

productId: '{{productId}}'

}}),

form-cart-delete.submit">

</div>

</template>

</amp-list>

46 of 57

Clicking button sets ID and submits form

<amp-list src="/cart_items" [src]="cartItemsList.items">

. . .

<template type="amp-mustache">

. . .

<div role="button" class="cart-remove-icon" tabindex="0"

on="tap: AMP.setState({

itemToRemove: {

productId: '{{productId}}'

}}),

form-cart-delete.submit">

</div>

</template>

</amp-list>

47 of 57

Form sends product ID and rebuilds cart

<form id="form-cart-delete"

method="POST" action-xhr="/delete-cart-item"

on="submit-success: AMP.setState(

{cartItemsList: event.response}

)">

<input type="hidden" name="productId" [value]="itemToRemove.productId">

</form>

48 of 57

<amp-list> refreshes cart

<amp-list src="/cart_items" [src]="cartItemsList.items">

. . .

<template type="amp-mustache">

. . .

<div role="button" class="cart-remove-icon" tabindex="0"

on="tap: AMP.setState({

itemToRemove: {

productId: '{{productId}}'

}}),

form-cart-delete.submit">

</div>

</template>

</amp-list>

49 of 57

https://amp.store

camp.samples.amp.dev

go.amp.dev/camp-code

50 of 57

50

51 of 57

Web Worker

DOM

WorkerDOM

postMessage

Main thread

52 of 57

Hello, world!

myscript.js

<amp-script layout="container" src="myscript.js">

<button>Hello amp-script!</button>

</amp-script>

const btn = document.querySelector('button');

btn.addEventListener('click', () => {

document.body.textContent += 'Hello World!';

});

document.body

53 of 57

WordPress AMP

54 of 57

55 of 57

WordPress AMP

  • AMP-first Experiences
  • Core Theme Support
  • Compatibility Tool
  • CSS Tree Shaking
  • AMP Stories (beta)

56 of 57

57 of 57

Thank you