AMP Conf 2019. April 17/18. Tokyo.
AMP
  • websites

amp-date-picker

Introduction

amp-date-picker is an AMP component which allows to select a single date or a range of dates. Its implementation is based on react-dates

Setup

Include the amp-date-picker component.

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

Include the amp-bind component to set variables based on the selected date.

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

Include the amp-mustache component to display an info panel below the date picker.

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

Include the amp-lightbox component to display a date picker inside a fullscreen lightbox view.

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

Include the amp-form component for creating forms.

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

In order to personalize amp-date-picker style, you can use classes such as CalendarMonth_caption which are inherited from react-dates. amp-date-picker also exposes CSS classes which you can use in CSS rule, like amp-date-picker-selecting, which is applied to the date input the user is editing.

<style amp-custom>
:root {
--color-primary: #005AF0;
--color-text-light: #fff;
--color-bg-light: #FAFAFC;
--space-2: 1rem;   /* 16px */
--space-1: 0.5rem; /* 8px */
}

.example-picker {
  display: flex;
}

.example-picker[mode="overlay"] {
  padding: var(--space-2);
}

.example-picker .CalendarMonth_caption {
  color: var(--color-text-light);
}

.example-picker [type="range"] .amp-date-picker-selecting {
  border-bottom-color: var(--color-primary);
  color: var(--color-primary);
}

.space-between > * + * {
  margin-left: var(--space-2);
}

#lb {
  background: var(--color-bg-light);
}

#lb .align-content-center {
  height: 100%;
}

.icon-input {
  background-image: url('data:image/svg+xml,<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1393.1 1500" style="enable-background:new 0 0 1393.1 1500;" xml:space="preserve"><path d="M107.2,1392.9h241.1v-241.1H107.2V1392.9z M401.9,1392.9h267.9v-241.1H401.9V1392.9z M107.2,1098.2h241.1V830.4H107.2 V1098.2z M401.9,1098.2h267.9V830.4H401.9V1098.2z M107.2,776.8h241.1V535.7H107.2V776.8z M723.4,1392.9h267.9v-241.1H723.4V1392.9z M401.9,776.8h267.9V535.7H401.9V776.8z M1044.8,1392.9H1286v-241.1h-241.1V1392.9z M723.4,1098.2h267.9V830.4H723.4V1098.2z M428.7,375V133.9c0-7.3-2.7-13.5-8-18.8c-5.3-5.3-11.6-8-18.8-8h-53.6c-7.3,0-13.5,2.7-18.8,8c-5.3,5.3-8,11.6-8,18.8V375 c0,7.3,2.7,13.5,8,18.8c5.3,5.3,11.6,8,18.8,8h53.6c7.3,0,13.5-2.7,18.8-8C426,388.5,428.7,382.3,428.7,375z M1044.8,1098.2H1286 V830.4h-241.1V1098.2z M723.4,776.8h267.9V535.7H723.4V776.8z M1044.8,776.8H1286V535.7h-241.1V776.8z M1071.6,375V133.9 c0-7.3-2.7-13.5-8-18.8c-5.3-5.3-11.6-8-18.8-8h-53.6c-7.3,0-13.5,2.7-18.8,8c-5.3,5.3-8,11.6-8,18.8V375c0,7.3,2.7,13.5,8,18.8 c5.3,5.3,11.6,8,18.8,8h53.6c7.3,0,13.5-2.7,18.8-8C1069,388.5,1071.6,382.3,1071.6,375z M1393.1,321.4v1071.4 c0,29-10.6,54.1-31.8,75.3c-21.2,21.2-46.3,31.8-75.3,31.8H107.2c-29,0-54.1-10.6-75.3-31.8C10.6,1447,0,1421.9,0,1392.9V321.4 c0-29,10.6-54.1,31.8-75.3s46.3-31.8,75.3-31.8h107.2v-80.4c0-36.8,13.1-68.4,39.3-94.6S311.4,0,348.3,0h53.6 c36.8,0,68.4,13.1,94.6,39.3c26.2,26.2,39.3,57.8,39.3,94.6v80.4h321.5v-80.4c0-36.8,13.1-68.4,39.3-94.6 C922.9,13.1,954.4,0,991.3,0h53.6c36.8,0,68.4,13.1,94.6,39.3s39.3,57.8,39.3,94.6v80.4H1286c29,0,54.1,10.6,75.3,31.8 C1382.5,267.3,1393.1,292.4,1393.1,321.4z"/></svg>');
  background-repeat: no-repeat;
  flex-shrink: 0;
  height: 28px;
  margin-top: var(--space-1);
  width: 27px;
}
</style>

Single date picker

amp-date-picker with type=single can be used for selecting a single date.

You can use amp-mustache with info-template attribute to show an info-panel below the calendar, here we are showing the date that you just selected. info-template also enables AMP binding making available variables which have been set with AMP.setState.

A placeholder is required for the component. For a single date, this can take the form:

<input amp-date-placeholder placeholder="Pick a date">. amp-date-picker introduces the clear and today actions. clear can be called after clicking on a button to clear the date selection. The today action allows users to quickly select the current date, and its offset argument chooses how many days from today to set the date.

<amp-date-picker id="simple-date-picker"
  type="single"
  mode="overlay"
  layout="container"
  on="select:AMP.setState({date1: event.date, dateType1: event.id})"
  format="YYYY-MM-DD"
  open-after-select
  input-selector="[name=date1]"
  class="example-picker space-between">
  <div class="icon-input"></div>
  <input name="date1"
    placeholder="Pick a date">
  <button on="tap: simple-date-picker.clear">Clear</button>
  <button on="tap: simple-date-picker.today">Today</button>
  <button on="tap: simple-date-picker.today(offset=1)">Tomorrow</button>
  <template type="amp-mustache"
    info-template>
    <span [text]="date1 != null ? 'You picked ' + date1 + '.' : 'You will see your chosen date here.'">You will see your chosen date here.</span>
  </template>
</amp-date-picker>

Custom date markup

In addition, you can also use amp-mustache to create templates for custom date markup, such as an icon instead of the number of the month. Here we are using a taco icon in place of the number of the month with a frequency of 2 weeks every Tuesday. Common use cases could be dates of the month where the price of an item is fixed to a specific number.

<amp-date-picker id="simple-date-picker-2"
  type="single"
  mode="overlay"
  layout="container"
  on="select:AMP.setState({date2: event.date, dateType2: event.id})"
  locale="en"
  format="YYYY-MM-DD"
  open-after-select
  input-selector="[name=date2]"
  class="example-picker space-between">
  <input class="border-none p0"
    name="date2"
    placeholder="Pick a date">
  <button on="tap: simple-date-picker-2.clear">Clear</button>
  <template type="amp-mustache"
    date-template
    dates="FREQ=WEEKLY;DTSTART=20180101T000000Z;INTERVAL=2;WKST=SU;BYDAY=TU"
    id="tacos2">
    <span>🌮</span>
    <span class="taco-tuesday"></span>
  </template>
  <template type="amp-mustache"
    info-template>
    <span [text]="date2 ? 'You picked ' + date2 + '.' +
      (dateType2 == 'tacos2' ? ' Happy Taco Tuesday!' : '') : ''">You will see your chosen date here.</span>
  </template>
</amp-date-picker>

Date Range Picker

amp-date-picker with type=range can be used for selecting a date range.

By default, amp-date-picker disables past dates, use min attribute to enable them.

<amp-date-picker type="range"
  mode="overlay"
  id="range-date-picker"
  on="
  select:
    AMP.setState({
        dates: event.dates,
        startDate: event.start,
        endDate: event.end
    })"
  format="YYYY-MM-DD"
  open-after-select
  min="2017-10-26"
  start-input-selector="#range-start"
  end-input-selector="#range-end"
  class="example-picker space-between">
  <input id="range-start"
    placeholder="Start date">
  <input id="range-end"
    placeholder="End date">
  <button on="tap:range-date-picker.clear">Clear</button>
  <template type="amp-mustache"
    info-template>
    <span [text]="(startDate && endDate ?
      'You picked ' + startDate.date + ' as start date and ' + endDate.date + ' as end date.' :
      'You will see your chosen dates here.')">
      You will see your chosen dates here.
    </span>
  </template>
</amp-date-picker>

External Configuration

It's possible to configure the amp-date-picker preferences by using an external json. We use the following JSON at the URL /json/amp-date-picker.json:

    {
      "templates": [{
        "id": "spooky",
        "dates": [
          "FREQ=WEEKLY;DTSTART=20180101T160000Z;BYDAY=MO",
          "FREQ=YEARLY;DTSTART=20180101T160000Z;WKST=SU;BYMONTH=10;BYMONTHDAY=31",
          "FREQ=MONTHLY;DTSTART=20180101T160000Z;WKST=SU;BYDAY=FR;BYMONTHDAY=13"
        ]
      }]
    }

For dates that match the list of dates in the JSON blob, the template with id="spooky" will be used to render that day in the calendar. In this case, these dates are Mondays, Friday the 13ths, and Halloween.

<amp-date-picker id="src-picker"
  type="single"
  mode="overlay"
  layout="container"
  format="YYYY-MM-DD"
  src="/static/samples/json/amp-date-picker.json"
  input-selector="#src-input"
  class="example-picker space-between">
  <input id="src-input"
    placeholder="Pick a date">
  <button on="tap: src-picker.clear">Clear</button>
  <template type="amp-mustache"
    date-template
    id="spooky">
    <span>🙀</span>
  </template>
</amp-date-picker>

Static date picker

amp-date-picker with mode="static" can display a calendar view. The static picker can be used with or without an attached input.

<amp-date-picker id="static-picker"
  type="single"
  mode="static"
  layout="fixed-height"
  height="360"
  format="YYYY-MM-DD"
  input-selector="#static-picker-input">
</amp-date-picker>

Highlighted and blocked attributes

amp-date-picker supports a range of attributes, for example highlighted and blocked. Find the complete list in the official doc.

The blocked attribute allows to specify a space separated list of ISO 8601 dates and RFC 5545 RRULEs specifying disallowed dates.

The highlighted attributes a space separated list of ISO 8601 dates and RFC 5545 RRULEs specifying dates displayed with a highlight style.

Here every Thursday is highlighted, while every weekend is blocked.

<amp-date-picker id="simple-date-picker-3"
  type="single"
  mode="static"
  layout="fixed-height"
  height="360"
  on="select:AMP.setState({date3: event.date ? event.date : ''})"
  locale="en"
  format="YYYY-MM-DD"
  highlighted="FREQ=WEEKLY;WKST=SU;BYDAY=TH"
  blocked="FREQ=WEEKLY;WKST=SU;BYDAY=SA,SU">
</amp-date-picker>

Allow-blocked-dates attribute

If the date picker uses type="range" and there are blocked dates that are allowed to be part of the range, the allow-blocked-dates attribute allows users to select ranges that include blocked dates.

<amp-date-picker id="simple-date-picker-4"
  type="range"
  mode="static"
  layout="fixed-height"
  height="360"
  on="select:AMP.setState({date4: event.date ? event.date : ''})"
  locale="en"
  format="YYYY-MM-DD"
  allow-blocked-ranges
  highlighted="FREQ=WEEKLY;WKST=SU;BYDAY=TH"
  blocked="FREQ=WEEKLY;WKST=SU;BYDAY=SA,SU">
</amp-date-picker>

amp-date-picker can display inside a modal lightbox. The activate event opens the lightbox if the user focuses the picker's connected input elements and presses the down arrow key. deactivate is triggered when the user presses escape when interacting with the calendar view. For a touch-only interface box, the on="tap:..." attribute opens the picker when the user taps on the input.

Choose your travel dates

<div>
  <p>Choose your travel dates</p>
  <input id="lb-start"
    placeholder="Start date"
    on="tap:lb.open"
    role="textbox"
    tabindex="0">
  <input id="lb-end"
    placeholder="End date"
    on="tap:lb.open"
    role="textbox"
    tabindex="0">
  <button on="tap:lb-picker.clear">Clear</button>
  <amp-lightbox id="lb"
    layout="nodisplay">
    <button on="tap:lb.close"
      tabindex="0">Close</button>
    <div class="align-content-center">
      <amp-date-picker id="lb-picker"
        type="range"
        mode="static"
        layout="fixed-height"
        height="360"
        format="MM/DD/YYYY"
        on="activate: lb.open;
            deactivate: lb.close;"
        start-input-selector="#lb-start"
        end-input-selector="#lb-end"></amp-date-picker>
    </div>
  </amp-lightbox>
</div>

Fullscreen lightbox date picker

amp-date-picker can also display as a fullscreen view inside a lightbox. The fullscreen attribute tells the date picker to take up the space in its container and allow its content to scroll vertically.

Choose your travel dates

<div>
  <p>Choose your travel dates</p>
  <input id="lb-fullscreen-start"
    placeholder="Start date"
    on="tap:lb-fullscreen.open"
    role="textbox"
    tabindex="0">
  <input id="lb-fullscreen-end"
    placeholder="End date"
    on="tap:lb-fullscreen.open"
    role="textbox"
    tabindex="0">
  <button on="tap:lb-fullscreen-picker.clear">Clear</button>
  <amp-lightbox id="lb-fullscreen"
    layout="nodisplay"
    scrollable>
    <button on="tap:lb-fullscreen.close"
      tabindex="0">Close</button>
    <amp-date-picker id="lb-fullscreen-picker"
      fullscreen
      layout="fill"
      mode="static"
      type="range"
      number-of-months="12"
      format="MM/DD/YYYY"
      on="activate: lb-fullscreen.open;
            deactivate: lb-fullscreen.close;"
      start-input-selector="#lb-fullscreen-start"
      end-input-selector="#lb-fullscreen-end"></amp-date-picker>
  </amp-lightbox>
</div>

Date picker in a form

amp-date-picker integrates with AMP forms. If you don't provide an input for a static picker, it will create a hidden input to submit in the form.

<form method="post"
  action-xhr="/components/amp-form/submit-form-xhr"
  target="_top">
  <amp-date-picker id="form-picker"
    type="single"
    mode="static"
    layout="fixed-height"
    height="360"
    format="YYYY-MM-DD">
  </amp-date-picker>
  <input type="submit">
  <div submit-success>
    <template type="amp-mustache">
      Success! Thanks for trying the
      <code>amp-form</code> demo!
    </template>
  </div>
  <div submit-error>
    <template type="amp-mustache">
      Error!
    </template>
  </div>
</form>

Date picker with amp-bind

amp-date-picker integrates with amp-bind. The min and max attributes can be used to update the min and max date.

<div>
  <amp-state id="binding">
    <script type="application/json">
      {
        "min": "",
        "max": ""
      }
    </script>
  </amp-state>
  <input on="change:AMP.setState({binding: {min: event.value}})"
    placeholder="Minimum date">
  <input on="change:AMP.setState({binding: {max: event.value}})"
    placeholder="Maximum date">
  <amp-date-picker id="bind-picker"
    type="single"
    mode="static"
    layout="fixed-height"
    height="360"
    format="MM/DD/YYYY"
    [min]="binding.min"
    [max]="binding.max">
  </amp-date-picker>
</div>
Need further explanation?

If the explanations on this page don't cover all of your questions feel free to reach out to other AMP users to discuss your exact use case.

Go to Stack Overflow
An unexplained feature?

The AMP project strongly encourages your participation and contributions! We hope you'll become an ongoing participant in our open source community but we also welcome one-off contributions for the issues you're particularly passionate about.

Edit sample on GitHub