amp-list

Edit on Github
Open in Playground

Introduction

The amp-list enables client-side rendering in AMP. Content can either be fetched from a JSON endpoint or locally from amp-state.

Setup

Import the amp-list component ...

<script async custom-element="amp-list" src="https://cdn.ampproject.org/v0/amp-list-0.1.js"></script>

... and the amp-mustache component in the header.

<script async custom-template="amp-mustache" src="https://cdn.ampproject.org/v0/amp-mustache-0.2.js"></script>

Import the amp-bind component for dynamically changing the content of an amp-list.

<script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>

Basic usage

The amp-list content is provided by a JSON CORS endpoint, which is defined by the src attribute. The URL's protocol must be HTTPS. The response must be a JSON object containing an array property items, for example:

{
  "items": [
    {
      "title": "amp-carousel",
      "url": "https://ampbyexample.com/components/amp-carousel"
    },
    ...
  ]
}

The list content is rendered via an amp-mustache template. The template can be specified either by id, or by using a nested element.

Example

<amp-list layout="fixed-height"
  height="100"
  src="https://ampbyexample.com/json/examples.json">
  <template type="amp-mustache">
    <div>
      <a href="{{url}}">{{title}}</a>
    </div>
  </template>
</amp-list>

Re-using an existing template

The template can also be specified using an ID of an existing template element.

Example

<template type="amp-mustache"
  id="amp-template-id">
  <div>
    <a href="{{url}}">{{title}}</a>
  </div>
</template>
<amp-list layout="fixed-height"
  height="100"
  src="https://ampbyexample.com/json/examples.json"
  template="amp-template-id">
</amp-list>

Handling list overflow

If the amp-list content requires more space than available, the AMP runtime will display the overflow element (if specified).

Example

Show more
<amp-list layout="fixed-height"
  height="48"
  src="https://ampbyexample.com/json/examples.json">
  <div overflow
    role="button"
    aria-label="Show more"
    class="list-overflow">
    Show more
  </div>
  <template type="amp-mustache">
    <div>
      <a href="{{url}}">{{title}}</a>
    </div>
  </template>
</amp-list>

Dynamic src

The content of an amp-list can be changed dynamically by modifying it's src value using amp-bind.

Example

<amp-list layout="fixed-height"
  height="100"
  src="https://ampbyexample.com/json/examples.json"
  [src]="srcUrl">
  <template type="amp-mustache">
    <div>
      <a href="{{url}}">{{title}}</a>
    </div>
  </template>
</amp-list>
<button on="tap:AMP.setState({ srcUrl: 'https://ampbyexample.com/json/examples2.json' })">Change source</button>

Rendering amp-state

This sample shows off once of amp-list's most powerful features: being able to directly render objects from amp-state, This is possible by binding the results of an amp-bind expression to the src attribute: [src]="items". To make sure that the amp-list resizes accordingly, we dynamically calculate the height based on the number of list elements: [height]="items.length * 24". The initial state (an empty list) is defined in an amp-state element.

Important: amp-bind expressions are not evaluated on page load, but only after an user interaction has taken place. Initial amp-list content still needs to be fetched from a JSON endpoint.

Example

<amp-state id="items">
  <script type="application/json">
    []
  </script>
</amp-state>
<amp-list layout="fixed-height"
  height="0"
  [src]="items"
  [height]="items.length * 24"
  single-item
  items=".">
  <template type="amp-mustache">
    <div>{{ . }}</div>
  </template>
</amp-list>
<button on="tap:AMP.setState({ items: items.splice(items.length, 0, 'item ' + items.length) })">
  Add item
</button>

Empty list content

If the list contains an empty array, you can use mustache inverted sections to print a message. For this to work, we have to use the single-item attribute and items attribute to be able to access the root items array inside the template.

Example

<amp-list layout="fixed-height"
  height="100"
  src="/json/examples-empty.json"
  [src]="emptyListSampleSrc || '/json/examples-empty.json'"
  single-item
  items="."
  reset-on-refresh>
  <template type="amp-mustache">
    {{#items}}
    <div>
      <a href="{{url}}">{{title}}</a>
    </div>
    {{/items}} {{^items}}
    <div>No items founds.</div>
    {{/items}}
  </template>
</amp-list>
<button on="tap:AMP.setState({ emptyListSampleSrc: 'https://ampbyexample.com/json/examples.json' })">
  Add items
</button>

Using a placeholder animation

You can use a custom placeholder like an animation to improve the user experience while the list is loading. We are using an endpoint which intentionally delays the response by 10 seconds.

Example

<amp-list id="amp-list-placeholder"
  noloading
  reset-on-refresh
  layout="fixed-height"
  height="654"
  src="https://ampbyexample.com/samples_templates/slow-json-with-items/?delay=10000">
  <div placeholder>
    <div class="product"></div>
    <div class="product"></div>
    <div class="product"></div>
    <div class="product"></div>
    <div class="product"></div>
    <div class="product"></div>
  </div>
  <template type="amp-mustache">
    <div class="product">
      <amp-img width="150"
        height="100"
        alt="{{name}}"
        src="{{img}}"></amp-img>
      <div>
        <div>{{name}}</div>
        <div>{{{stars}}}</div>
        <div>${{price}}</div>
      </div>
    </div>
  </template>
</amp-list>

Triggering refresh

You can use the refresh action to trigger a refresh on amp-list. Notice how we are using reset-on-refresh attribute to ensure that the placeholder is reloaded.

Example

<button on="tap:myAmpList.refresh">Refresh list</button>
<amp-list id="myAmpList"
  reset-on-refresh
  layout="fixed-height"
  height="600"
  src="https://ampbyexample.com/samples_templates/slow-json-with-items/?delay=1000">
  <template type="amp-mustache">
    <div class="product">
      <amp-img width="150"
        height="100"
        alt="{{name}}"
        src="{{img}}"></amp-img>
      <div>
        <div>{{name}}</div>
        <div>{{{stars}}}</div>
        <div>${{price}}</div>
      </div>
    </div>
  </template>
</amp-list>