amp-form

Edit on Github
Open in Playground View Demo

Experimental Mode

This example uses the following experimental feature: [amp-form-verifiers]. Enable the experiment via the button below. Some components require the AMP Dev Channel to be enabled as well. Learn more here.

Enable Dev Channel

Introduction

The amp-form extension allows the usage of forms and input fields in an AMP document. amp-form allows HTTP and XHR (XMLHttpRequest) form submissions. An HTTP form submission loads a new page, while an XHR form submission doesn't require a page reload.

Setup

Import the library.

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

Customize success or error messages by using amp-form-submit-success and amp-form-submit-error classes.

<style amp-custom>
form.amp-form-submit-success [submit-success],
form.amp-form-submit-error [submit-error]{
  margin-top: 16px;
}
form.amp-form-submit-success [submit-success] {
  color: green;
}
form.amp-form-submit-error [submit-error] {
  color: red;
}
form.amp-form-submit-success.hide-inputs > input {
  display: none;
}
</style>

Form Submission with Page Reload

Use the action attribute to specify a server-endpoint which should handle the form input. This works only for GET requests. The URL must be HTTPS. The following sample uses type="search" to emulate a search. The search button will trigger a page reload.

Please find security considerations to check best practices when choosing GET or POST methods.

You can find the code for the server endpoint used in this demo at /backend/amp-form.go.

Example

<form method="GET"
  class="p2"
  action="/components/amp-form/submit-form"
  target="_top">
  <div class="ampstart-input inline-block relative mb3">
    <input type="search"
      placeholder="Search..."
      name="googlesearch">
  </div>
  <input type="submit"
    value="OK"
    class="ampstart-btn caps">
</form>

Form Submission with Page Update

Use the action-xhr attribute to submit the form via XMLHttpRequest (XHR). You can use amp-mustache templates to show custom success or error messages, using data sent by the server endpoint as JSON. For example, if the server sends {"foo": "bar"}, you can use use {{foo}} in the template to render bar.

The amp-form component displays submit-success or submit-error elements based on the response and renders the template data inside these two elements. The submit-success and submit-error elements must be direct children of form.

Example

<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-input-text-xhr"
  target="_top">
  <div class="ampstart-input inline-block relative m0 p0 mb3">
    <input type="text"
      class="block border-none p0 m0"
      name="name"
      placeholder="Name..."
      required>
    <input type="email"
      class="block border-none p0 m0"
      name="email"
      placeholder="Email..."
      required>
  </div>
  <input type="submit"
    value="Subscribe"
    class="ampstart-btn caps">
  <div submit-success>
    <template type="amp-mustache">
      Success! Thanks {{name}} for trying the
      <code>amp-form</code> demo! Try to insert the word "error" as a name input in the form to see how
      <code>amp-form</code> handles errors.
    </template>
  </div>
  <div submit-error>
    <template type="amp-mustache">
      Error! Thanks {{name}} for trying the
      <code>amp-form</code> demo with an error response.
    </template>
  </div>
</form>

Form Custom Validation

The amp-form extension allows you to build your own custom validation UI by using the custom-validation-reporting, read here about the different strategies.

Use show-all-on-submit strategy to ensure all the validation messages are shown when the user submits the form.

Example

Please enter your first and last name separated by a space (e.g. Jane Miller)
<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-input-text-xhr"
  target="_top"
  custom-validation-reporting="show-all-on-submit">
  <div class="ampstart-input inline-block relative m0 p0 mb3">
    <input type="text"
      class="block border-none p0 m0"
      id="show-all-on-submit-name"
      name="name"
      placeholder="Name..."
      required
      pattern="\w+\s\w+">
    <span visible-when-invalid="valueMissing"
      validation-for="show-all-on-submit-name"></span>
    <span visible-when-invalid="patternMismatch"
      validation-for="show-all-on-submit-name">
      Please enter your first and last name separated by a space (e.g. Jane Miller)
    </span>
    <input type="email"
      class="block border-none p0 m0"
      id="show-all-on-submit-email"
      name="email"
      placeholder="Email..."
      required>
    <span visible-when-invalid="valueMissing"
      validation-for="show-all-on-submit-email"></span>
    <span visible-when-invalid="typeMismatch"
      validation-for="show-all-on-submit-email"></span>
  </div>
  <input type="submit"
    value="Subscribe"
    class="ampstart-btn caps">
  <div submit-success>
    <template type="amp-mustache">
      Success! Thanks {{name}} for trying the
      <code>amp-form</code> demo! Try to insert the word "error" as a name input in the form to see how
      <code>amp-form</code> handles errors.
    </template>
  </div>
  <div submit-error>
    <template type="amp-mustache">
      Error! Thanks {{name}} for trying the
      <code>amp-form</code> demo with an error response.
    </template>
  </div>
</form>

Use show-first-on-submit strategy to show the first validation message when the user submit the form.

Example

Please enter your first and last name separated by a space (e.g. Jane Miller)
<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-input-text-xhr"
  target="_top"
  custom-validation-reporting="show-first-on-submit">
  <div class="ampstart-input inline-block relative m0 p0 mb3">
    <input type="text"
      class="block border-none p0 m0"
      id="show-first-on-submit-name"
      name="name"
      placeholder="Name..."
      required
      pattern="\w+\s\w+">
    <span visible-when-invalid="valueMissing"
      validation-for="show-first-on-submit-name"></span>
    <span visible-when-invalid="patternMismatch"
      validation-for="show-first-on-submit-name">
      Please enter your first and last name separated by a space (e.g. Jane Miller)
    </span>
    <input type="email"
      class="block border-none p0 m0"
      id="show-first-on-submit-email"
      name="email"
      placeholder="Email..."
      required>
    <span visible-when-invalid="valueMissing"
      validation-for="show-first-on-submit-email"></span>
    <span visible-when-invalid="typeMismatch"
      validation-for="show-first-on-submit-email"></span>
  </div>
  <input type="submit"
    value="Subscribe"
    class="ampstart-btn caps">
  <div submit-success>
    <template type="amp-mustache">
      Success! Thanks {{name}} for trying the
      <code>amp-form</code> demo! Try to insert the word "error" as a name input in the form to see how
      <code>amp-form</code> handles errors.
    </template>
  </div>
  <div submit-error>
    <template type="amp-mustache">
      Error! Thanks {{name}} for trying the
      <code>amp-form</code> demo with an error response.
    </template>
  </div>
</form>

Use as-you-go strategy to show validation messages as the user is interacting with the form.

Example

Please enter your first and last name separated by a space (e.g. Jane Miller)
<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-input-text-xhr"
  target="_top"
  custom-validation-reporting="as-you-go">
  <div class="ampstart-input inline-block relative m0 p0 mb3">
    <input type="text"
      class="block border-none p0 m0"
      id="as-you-go-name"
      name="name"
      placeholder="Name..."
      required
      pattern="\w+\s\w+">
    <span visible-when-invalid="valueMissing"
      validation-for="as-you-go-name"></span>
    <span visible-when-invalid="patternMismatch"
      validation-for="as-you-go-name">
      Please enter your first and last name separated by a space (e.g. Jane Miller)
    </span>
    <input type="email"
      class="block border-none p0 m0"
      id="as-you-go-email"
      name="email"
      placeholder="Email..."
      required>
    <span visible-when-invalid="valueMissing"
      validation-for="as-you-go-email"></span>
    <span visible-when-invalid="typeMismatch"
      validation-for="as-you-go-email"></span>
  </div>
  <input type="submit"
    value="Subscribe"
    class="ampstart-btn caps">
  <div submit-success>
    <template type="amp-mustache">
      Success! Thanks {{name}} for trying the
      <code>amp-form</code> demo! Try to insert the word "error" as a name input in the form to see how
      <code>amp-form</code> handles errors.
    </template>
  </div>
  <div submit-error>
    <template type="amp-mustache">
      Error! Thanks {{name}} for trying the
      <code>amp-form</code> demo with an error response.
    </template>
  </div>
</form>

Form Verification

Form verification enables asynchronous validation of form fields. As a user fills out a form with verification enabled, amp-form sends the fields to the verify-xhr URL to check their values using logic on the server. If an error is found, such as a username being taken, it will show as a validation error in the form.

Read here for complete documentation.

Use the verify-xhr attribute to enable the form verification feature.

Form verification can combine with custom error reporting using visible-when-invalid="customError". When amp-form receives errors from the XHR response, it sets the customError validity on offending elements. Since AMP uses the HTML5 Form Constraint Validation API, it is easy for form verification errors to interact with standard form validation messages.

In the submit-error template, you can choose how to render verification error message using the verifyErrors list. These will only display if the user submits the form before the asynchronous verification response completes.

Example

That username is already taken Invalid character in username
<form method="post"
  class="p2"
  action-xhr="/components/amp-form/verify-form-input-text-xhr"
  verify-xhr="/components/amp-form/verify-form-input-text-xhr"
  target="_top"
  custom-validation-reporting="as-you-go">
  <div class="ampstart-input inline-block relative m0 p0 mb3">
    <input type="text"
      class="block border-none p0 m0"
      id="verification-username"
      name="username"
      placeholder="Username..."
      required
      pattern="\w+">
    <span visible-when-invalid="customError"
      validation-for="verification-username">That username is already taken</span>
    <span visible-when-invalid="patternMismatch"
      validation-for="verification-username">Invalid character in username</span>
  </div>
  <input type="submit"
    value="Check"
    class="ampstart-btn caps">
  <div submit-success>
    <template type="amp-mustache">
      Success! Thanks {{name}} for trying the
      <code>amp-form</code> demo! Try to insert the word "error" as a name input in the form to see how
      <code>amp-form</code> handles errors.
    </template>
  </div>
  <div submit-error>
    <template type="amp-mustache">
      {{#verifyErrors}}
      <p>{{message}}</p>
      {{/verifyErrors}} {{^verifyErrors}}
      <p>Something went wrong. Try again later?</p>
      {{/verifyErrors}}
      <p>Error! Thanks {{name}} for trying the
        <code>amp-form</code> demo with an error response.</p>
    </template>
  </div>
</form>

Hiding input fields after success

Use the amp-form-submit-success class to hide input fields after a successful submission. The following CSS rule hides all form input fields after successful form submission:

form.amp-form-submit-success > input {
  display: none
}

Example

<form class="p3 hide-inputs"
  method="post"
  action-xhr="/components/amp-form/submit-form-input-text-xhr"
  target="_top">
  <div class="ampstart-input inline-block relative mb3">
    <input type="text"
      name="name"
      placeholder="Name..."
      required>
  </div>
  <input type="submit"
    value="Subscribe"
    class="ampstart-btn caps">
  <div submit-success>
    <template type="amp-mustache">
      Success! Thanks {{name}} for trying the
      <code>amp-form</code> demo! Try to insert the word "error" as a name input in the form to see how
      <code>amp-form</code> handles errors.
    </template>
  </div>
  <div submit-error>
    <template type="amp-mustache">
      Error! Thanks {{name}} for trying the
      <code>amp-form</code> demo with an error response.
    </template>
  </div>
</form>

Other form input samples

amp-form supports all HTML5 form types with the exception of file, password and image. Use type="date" for input fields that should contain a date.

Example

<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-xhr"
  target="_top">
  <div class="ampstart-input inline-block relative mb3">
    <input name="select-date"
      type="date"
      value="2020-12-30">
  </div>
  <input type="submit"
    value="OK"
    class="ampstart-btn caps">
  <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>

Use type="month" for input fields that should contain a month.

Example

<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-xhr"
  target="_top">
  <div class="ampstart-input inline-block relative mb3">
    <input name="select-month"
      type="month"
      value="2020-12">
  </div>
  <input type="submit"
    value="OK"
    class="ampstart-btn caps">
  <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>

Use type="week" for input fields that should contain a week.

Example

<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-xhr"
  target="_top">
  <div class="ampstart-input inline-block relative mb3">
    <input type="week"
      name="week_year">
  </div>
  <input type="submit"
    value="OK"
    class="ampstart-btn caps">
  <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>

Use type="datetime-local" for input fields that should contain a date and time.

Example

<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-xhr"
  target="_top">
  <div class="ampstart-input inline-block relative mb3">
    <input name="select-datetime"
      type="datetime-local"
      value="2020-12-30T12:34:56">
  </div>
  <input type="submit"
    value="OK"
    class="ampstart-btn caps">
  <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>

Use type="time" for input fields that should contain a time.

Example

<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-xhr"
  target="_top">
  <div class="ampstart-input inline-block relative mb3">
    <input type="time"
      name="time_now">
  </div>
  <input type="submit"
    value="OK"
    class="ampstart-btn caps">
  <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>

Use type="checkbox" to let the user select ZERO or MORE options of a limited number of choices.

Example

<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-xhr"
  target="_top">
  <div class="ampstart-input ampstart-input-chk inline-block relative mb3 mr1">
    <input type="checkbox"
      id="animal1"
      name="animal1"
      class="relative"
      value="Cats">
    <label for="animal1">I like cats</label>
  </div>
  <div class="ampstart-input ampstart-input-chk inline-block relative mb3 mr1">
    <input type="checkbox"
      id="animal2"
      name="animal2"
      class="relative"
      value="Dogs">
    <label for="animal2"> I like dogs </label>
  </div>
  <button type="submit"
    value="OK"
    class="ampstart-btn caps">OK</button>
  <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>

Use type="email" for input fields that should contain an e-mail address.

Example

<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-xhr"
  target="_top">
  <div class="ampstart-input inline-block relative mb3">
    <input type="email"
      name="email"
      placeholder="Email...">
  </div>
  <input type="submit"
    value="OK"
    class="ampstart-btn caps">
  <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>

Use type="hidden" to define a field not visible to a user.

Example

<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-xhr"
  target="_top">
  <input type="hidden"
    name="city"
    value="London">
  <input type="submit"
    value="OK"
    class="ampstart-btn caps">
  <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>

Use type="number" for input fields that should contain a numeric value.

Example

<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-xhr"
  target="_top">
  <div class="ampstart-input inline-block relative mb3">
    <input type="number"
      name="quantity"
      min="1"
      max="5">
  </div>
  <input type="submit"
    value="OK"
    class="ampstart-btn caps">
  <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>

Use type="radio" to let a user select ONLY ONE of a limited number of choices.

Example

<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-xhr"
  target="_top">
  <div class="ampstart-input ampstart-input-radio inline-block relative mb3">
    <input type="radio"
      id="cat"
      class="relative"
      name="favourite animal"
      value="cat"
      checked>
    <label for="cat">Cat</label>
  </div>
  <div class="ampstart-input ampstart-input-radio inline-block relative m0 p0 mb3 ">
    <input type="radio"
      id="dog"
      class="relative"
      name="favourite animal"
      value="dog">
    <label for="dog">Dog</label>
  </div>
  <div class="ampstart-input ampstart-input-radio inline-block relative m0 p0 mb3 ">
    <input type="radio"
      id="other"
      class="relative"
      name="favourite animal"
      value="other">
    <label for="other">Other</label>
  </div>
  <input type="submit"
    value="OK"
    class="ampstart-btn caps">
  <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>

Use type="range" for input fields that should contain a value within a range.

Example

<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-xhr"
  target="_top">
  <div class=" ampstart-input inline-block relative mb3">
    <input type="range"
      name="points"
      min="0"
      max="10">
  </div>
  <input type="submit"
    value="OK"
    class="ampstart-btn caps">
  <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>

Use type="tel" for input fields that should contain a telephone number.

Example

<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-xhr"
  target="_top">
  <div class="ampstart-input inline-block relative mb3">
    <input type="tel"
      name="my_tel"
      placeholder="Telephone...">
  </div>
  <input type="submit"
    value="OK"
    class="ampstart-btn caps">
  <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>

Use type="url" for input fields that should contain a URL address.

Example

<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-xhr"
  target="_top">
  <div class="ampstart-input inline-block relative mb3">
    <input type="url"
      placeholder="URL..."
      name="website">
  </div>
  <input type="submit"
    value="OK"
    class="ampstart-btn caps">
  <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>

Use type="reset" to clear input fields.

Example

<form method="post"
  class="p2"
  action-xhr="/components/amp-form/submit-form-xhr"
  target="_top">
  <div class="ampstart-input inline-block relative mb3">
    <input type="text"
      placeholder="Some text...">
  </div>
  <div>
    <input type="submit"
      value="OK"
      class="ampstart-btn caps">
    <input type="reset"
      value="Reset"
      class="ampstart-btn caps">
  </div>
  <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>

Use select element for dropdowns.

Example

<form method="post"
  action-xhr="/components/amp-form/submit-form-xhr"
  target="_top"
  class="p2">
  <div class="ampstart-input inline-block relative mb3">
    <select name="cars"
      id="cars">
      <option value="volvo">Volvo</option>
      <option value="saab">Saab</option>
      <option value="fiat">Fiat</option>
      <option value="audi">Audi</option>
    </select>
    <label for="cars"
      class="absolute top-0 right-0 bottom-0 left-0">Select a car</label>
  </div>
  <input type="submit"
    value="OK"
    class="ampstart-btn caps">
  <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>