In this codelab, you’ll create a checkout form that leverages the autofill API to help users quickly, and accurately, complete their purchases. In the process you’ll learn how to use Polymer’s Gold Elements, layout classes, and the basics of working with the iron-form element.

What you’ll learn

What you’ll need

How would rate your experience with Polymer?

NoviceIntermediateAdvanced

Create a new project

The first time you run Chrome Dev Editor it will ask you to setup your workspace environment.

Fire up Chrome Dev Editor and start a new project:

  1. Click to start a new project.
  2. Enter "PolymerCheckoutForm" as the Project name.
  3. In the Project type dropdown, select "JavaScript web app (using Polymer paper elements)".
  4. Click the Create button.

Chrome Dev Editor creates a basic scaffold for your Polymer app. In the background, it also uses Bower to download and install a list of dependencies (including the Polymer core library) into the bower_components/ folder. Fetching the components may take some time if your internet connection is slow.

Project structure

PolymerCheckoutForm/
  bower_components/ <!-- installed dependencies from Bower -->
  bower.json  <!-- Bower metadata files used for managing deps -->
  index.html  <!-- your app -->
  main.js
  styles.css

Preview the app

At any point, select the index.html file and hit the  button in the top toolbar to run the app. Chrome Dev Editor fires up a web server and navigates to the index.html page. This is a great way to preview changes as you make them.

Next up

At this point the app doesn't do much. Let’s start by creating a container to hold our form.

The <paper-material> element is a generic container that resembles a lifted sheet of paper.

Install the element sets

Normally, you'd run bower install polymerelements/paper-material --save on the command line to install <paper-material> and save it as a dependency. However, Chrome Dev Editor does not have a command line for running Bower commands. Instead, you need to manually edit bower.json to include the elements you want, then run Chrome Dev Editor's Bower Update feature. Bower Update checks the dependencies in bower.json and installs any missing ones.

Because this tutorial calls for elements from Polymer’s paper, iron, and gold element sets, add all three to your bower.json file.

  1. Edit bower.json and add the paper, iron, and gold sets to the dependencies object:
"dependencies": {
  "paper-elements": "polymerelements/paper-elements#^1.0.4",
  "iron-elements": "polymerelements/iron-elements#^1.0.3",
  "gold-elements": "polymerelements/gold-elements#^1.0.1"
}
  1. Right-click the bower.json filename in the editor.
  2. Select Bower Update from the context menu.

The download may take a few seconds. You can verify that <paper-material> (and any dependencies) were installed by checking that bower_components/paper-material/ was created and populated.

Use the <paper-material> element

To employ <paper-material>, you need to:

  1. Use an HTML Import to load it in index.html.
  2. Declare an instance of the element on the page.

Because the default project from Chrome Dev Editor has waaaaay more stuff than you need for this tutorial, replace the contents of the index.html file so it looks like this:

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">

    <title>Polymer Checkout Form</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Web Components -->
    <script src="bower_components/webcomponentsjs/webcomponents-lite.min.js">
    </script>
    <!-- Imports will go here -->
    <link rel="stylesheet" href="styles.css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto">
  </head>
  <body unresolved>

  </body>
</html>

Find the line that says <!-- Imports will go here --> and replace it with the following import.

<link rel="import" href="bower_components/paper-material/paper-material.html">

Now that the import is in place you’re ready to use your element. Update the contents of <body> with an instance of <paper-material>:

index.html

<body unresolved>
  <paper-material class="card" elevation="1">
    Hello World!
  </paper-material>
</body>

There’s a few interesting things going on here. You may have noticed the unresolved attribute on <body> and wondered what that’s all about? In browsers that support Web Components, rendering of the page is blocked until all component definitions have loaded (unless you add an async attribute to your imports). This is to prevent a “Flash of Unstyled Content”, or FOUC. Coincidentally, this is also how CSS works—did you notice that both HTML Imports and CSS use <link> tags? This is a great feature of Web Components, but because not all browsers fully support the standards yet, we need to polyfill this behavior, and that’s exactly what unresolved does. It hides the content of the page until all of your imports have loaded, and only then does it reveal the finished masterpiece!

Check out the <paper-material> element and you’ll notice it has a class for styling (which you’ll use in just a moment) as well as an attribute, elevation, that defines how deep of a shadow it will cast on the page. One of the best aspects of working with custom elements is that they’re so easily configured in markup. In a moment you’ll preview the app and when you do, be sure to go back and change this attribute. Set the elevation to 0 or 5 or some whole number in between to see how it changes.

Give it some style!

Open styles.css and replace its content with the following styles:

styles.css

body {
  font-family: 'Roboto', 'Noto', sans-serif;
  font-size: 14px;
  margin: 0;
  padding: 24px;
  background-color: #FAFAFA;
}

.card {
  background: #FFFFFF;
  max-width: 400px;
  padding: 24px;
  margin: 0 auto;
}

This will setup your typography and give the <paper-material> element (which has the class card) some basic dimensions.

Run the app

If you haven't already done so, hit the  button. At this point, you should see a card with a bit of text inside of it.

Next up

It’s a start, but there’s still a lot to do! In the next step you’ll build out the form element and test that it autofills.

To make the form truly reusable, you can create a custom element to hold its definition.

  1. Right-click on the PolymerCheckoutForm project in the sidebar
  2. Select New File
  3. Name the new file checkout-form.html and click Create

In checkout-form.html, update the HTML so it looks like the following:

checkout-form.html

<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="bower_components/iron-flex-layout/classes/iron-flex-layout.html">

<dom-module id="checkout-form">

  <template>
    <style></style>
  </template>

  <script>
    Polymer({

      is: 'checkout-form'

    });
  </script>

</dom-module>

This is pretty standard boilerplate for creating a new Polymer element. At the top you’re importing dependencies to ensure they’re loaded before your element tries to interact with them.

Next comes the <dom-module>, which has an id of checkout-form. The <template> contained within the <dom-module> is where you’ll put all of the markup for your element. Anytime someone uses an instance of <checkout-form>, this is the markup that will get stamped out to the page. You can style this markup using a built-in <style> tag.

Finally there is a <script> tag in which you call the Polymer constructor, passing an object which defines the prototype for your element. Notice how the is property in the prototype matches the id of the <dom-module>? That’s so the two can find each other later when you eventually concatenate and minify all of your imports into one big bundle for production.

One line that’s special is this one right here:

<link rel="import" href="bower_components/iron-flex-layout/classes/iron-flex-layout.html">

The iron-flex-layout import contains a stylesheet of useful classes for working with flexbox. If you’ve never worked with Flexbox before, prepare to have your life changed! Flexbox makes the process of doing CSS layout much more manageable. Once you learn how to use it you’ll never want to go back. Normally, working with flexbox requires a number of CSS vendor prefixes and oddly-named properties, but the helpful stylesheet provided by iron-flex-layout smoothes over all of those quirks.

Give your form some branding

Let’s use Flexbox to put a company header on our form. Update the <template> with the following content.

checkout-form.html

<template>
  <style></style>
  <div class="horizontal layout center form-title">
    <div class="avatar" item-icon></div>
    <div class="flex company">ACME Goods Co.</div>
  </div>
</template>

Notice the classes horizontal, layout, and center on the first <div>? Those are flexbox classes from iron-flex-layout. They translate to the following styles: “Using flexbox, layout my children horizontally and vertically align their center points”. Similarly, the flex class on the last child translates to: “Flex to fill as much of my parent container as possible.” Note that there is also a form-title class on the parent <div>. That’s a custom class that you’ll use for styling later.

The next step is to update the styles for these <div>s so they actually look like our fake company’s branding.

<style>
  :host {
    display: block;
  }

  .form-title {
    margin-bottom: 20px;
  }

  .avatar {
    display: inline-block;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    overflow: hidden;
    background: #3367d6;
    margin-right: 20px;
  }

  .company {
    color: #3367d6;
    font-size: 20px;
    font-weight: 200;
  }
</style>

There’s nothing too fancy about the above styles, with the exception of the :host selector. When an element needs to refer to itself it can do so with :host. In this case, the element is telling the world that it should display: block. By default, all custom elements are set to display: inline.

Adding the form to your page

In the <head> of index.html, after the import for paper-material.html, add another import for checkout-form.html

index.html

<link rel="import" href="bower_components/paper-material/paper-material.html">
<link rel="import" href="checkout-form.html">

Finally, drop an instance of the <checkout-form> tag into your <paper-material> element.

<body unresolved>
  <paper-material class="card" elevation="1">
    <checkout-form></checkout-form>
  </paper-material>
</body>

Run the app

Hit the  button! At this point, you should see the beginnings of a form with our company’s branding at the top. Notice how the <div>’s are laid out horizontally and have their centers aligned? That’s flexbox in action!

Next up

Learn to use Iron, Paper, and Gold elements to autofill the form.

To wrap up the look of the form, you’ll need to use a handful of Iron, Paper, and Gold elements.

In checkout-form.html, add new HTML Imports for these components to the top of the file, after the other imports.

checkout-form.html

<link rel="import" href="bower_components/iron-form/iron-form.html">
<link rel="import" href="bower_components/paper-input/paper-input.html">
<link rel="import" href="bower_components/paper-button/paper-button.html">
<link rel="import" href="bower_components/gold-cc-input/gold-cc-input.html">
<link rel="import" href="bower_components/gold-email-input/gold-email-input.html">
<link rel="import" href="bower_components/gold-cc-cvc-input/gold-cc-cvc-input.html">
<link rel="import" href="bower_components/gold-cc-expiration-input/gold-cc-expiration-input.html">

Combining iron-form with custom input elements

Add the following HTML to checkout-form.html. You’ll want to add this inside of the <template>, after our fake company’s branding.

checkout-form.html

<form is="iron-form" id="form" method="post" action="/checkout">
  <paper-input name="name" label="Name on card" required autocomplete="cc-name"></paper-input>
</form>

If you place a custom element inside a native <form> tag, it won't work. The native <form> only supports a subset of child elements. Enter <iron-form>. <iron-form> behaves similarly to the native <form>, but enables you to submit content for any child element that implements the Polymer.IronFormElementBehavior.

Notice that the iron-form element extends the native form tag. This is so we can piggyback on the behavior of collecting values for native elements, while adding additional behavior to work with custom input elements. The form takes method and action attributes to specify how your requests should be sent. Note that these are standard attributes inherited from the native <form> tag. For this demo we won’t be building a backend, but now you know how to use them in your future apps.

Take a look at the attributes on the <paper-input> element. name is the name of the field that will be submitted as part of the form content. label is a line of text that will act as a placeholder until the user starts typing; once the user has begun entering text this label will float above what they’ve entered so they still have some context. required indicates that the form can’t be submitted unless this field has been filled out. Lastly, autocomplete specifies which part of the autofill API this field should hook into. The value cc-name tells the autofill API to prompt the user for the name on their credit card, if they have it saved in their browser already.

If you switch back to index.html and press you’ll see the <paper-input> is working mostly as expected, but we’re not seeing any autofill behavior yet. That’s because we still need to add a few more fields.

Instead of using paper-input elements for the remaining credit card fields, let’s switch to using gold-* elements. The Gold Elements work just like <paper-input> fields but also include built-in support for validation, default labels, and already contain the proper autocomplete attributes.

Add the following to checkout-form.html after the <paper-input> for cc-name.

checkout-form.html

<form is="iron-form" id="form" method="post" action="/checkout">

  ...

  <gold-cc-input name="cc-number" required auto-validate card-type="{{typeOfCard}}"></gold-cc-input>

</form>

The <gold-cc-input> field will prompt the user for their Card number, and because it contains an auto-validate attribute, it will also check that the card number is valid. After it has verified that the card is valid, it will update its cardType property to indicate what kind of card was entered (Visa, American Express, etc). You can bind to this value with the card-type attribute. By creating a scope variable, typeOfCard, that’s bound to the value of cardType, you can tell other elements what kind of card they should try to validate against (and you can display a cool graphic of the card, as you’ll see in a minute).

The last two pieces of data that you’ll need are the expiration date and the Card Verification Value Code (often referred to as the CVC or CVV). Let’s use some more Gold elements for those fields.

checkout-form.html

<form is="iron-form" id="form" method="post" action="/checkout">

  ...
  
  <div class="horizontal layout">
    <gold-cc-expiration-input name="cc-expiration" required auto-validate label="Expiration"></gold-cc-expiration-input>
    <gold-cc-cvc-input name="cc-cvc" required auto-validate card-type="[[typeOfCard]]"></gold-cc-cvc-input>
  </div>

</form>

Because the fields are pretty short, you can have them both on the same line by wrapping them in a <div> and using layout attributes to do another horizontal layout (similar to the fake company branding from earlier).

Also notice that the <gold-cc-cvc-input> element has a binding for card-type. Because it’s using square brackets it means this is a one way binding, so this element can only receive data. In this instance, as soon as <gold-cc-input> knows what type of card the user has entered, it pushes that information to <gold-cc-cvc-input>. Because different card types have different CVC values (Visa uses a 3 digit CVC, and American Express uses a 4 digit CVC), this information helps the <gold-cc-cvc-input> to better validate the card.

The last thing to do is add a bit of styling so the expiration date looks nice on the same row as the CVC. Add this to the end of the element’s <style> tag.

checkout-form.html

gold-cc-expiration-input {
  width: 50%;
  margin-right: 20px;
}

Run the app

Switch to index.html and hit the  button! You should see a very nice looking Material Design form. If you try to fill it out, you’ll get a warning saying credit card filling has been disabled because you’re not on a secure connection (in other words, your form is not being served over https).

This is great because it demonstrates that the autofill API is trying to kick-in and take advantage of our elements, but also kind of a bummer because we can’t test the real form just yet. Don’t worry, we can finish setting things up and then do a final test on a real server.

Next up

Adding a pay button to submit the form.

What good’s a checkout form if the user can’t actually submit it? In this last section you’ll add a pay button that sets the form in motion and makes you (hypothetically) rich!

In checkout-form.html add a <paper-button> with the following markup:

checkout-form.html

<form is="iron-form" id="form" method="post" action="/checkout">
  ... <!-- Our form fields -->

  <paper-button on-click="_submit">Pay</paper-button>
</form>

Polymer makes it easy to wire up event handlers on your elements using on-* syntax. Polymer will handle setting up the listeners when your element is added to the DOM, and most importantly, removing them when your element is removed from the DOM. This helps prevent potential memory leaks!

You’ll need to provide a _submit method which is run in response to the event.

checkout-form.html

<script>
  Polymer({

    is: 'checkout-form',

    _submit: function() {
      this.$.form.submit();
    }

  });
</script>

The _submit method is prefixed with an underscore to signify to the outside world that it’s private. Inside the method, call this.$.form.submit(). Calling this.$.form will return a reference to the the iron-form using Polymer’s Automatic Node Finding (explained below) and instruct the form to submit via AJAX.

Add a little CSS to have the button fill the bottom of the form. You can add this at the bottom of the <style> tag inside of checkout-form.html

checkout-form.html

paper-button {
  background-color: #4285f4;
  color: #fff;
  margin-top: 50px;
  width: 100%;
}

Because we don’t have an actual backend for processing credit cards (and that would probably not be a very safe thing to try to set up during a code lab!) let’s listen for the form submit event and just log something cheerful to the console.

Rather than write out another event handler in markup, let’s use Polymer’s listeners object. Similar to automatic node finding, the listeners object will find any element with an id so you can use it to listen directly to the iron-form element. Update your element’s prototype so it looks like this:

checkout-form.html

Polymer({

  is: 'checkout-form',

  listeners: {
    'form.iron-form-submit': '_handleFormSubmit'
  },

  _submit: function() {
    this.$.form.submit();
  },

  _handleFormSubmit: function() {
    console.log('Form submitted successfully! You are so rich now!');
  }

});

Try the live version

You can switch back to index.html and hit the  button to see a local version of your form running. Like last time, you won’t be able to autofill the form, though you can manually type in values and hit the submit button to see that the right thing gets logged to the console. Because there’s no handler for the /checkout URL, that bit will return an error. In a real app however, you could send back a response and let the user know whether their payment was accepted or rejected.

To test out the autofill features, take a look at this version of the form, running with https on Firebase. Don’t worry, none of your information is stored or submitted anywhere, so if you happen to autofill with a real credit card it’ll be ok. I promise. :)

If you’ve previously saved your credit card in Chrome, it should prompt you to autocomplete as soon as you start typing your name. If all goes well you should see something that looks like this (fake credit card provided).

Depending on how you’ve previously saved your card, the CVC number may or may not autofill.

So there you have it! A checkout form which you can apply your own branding to. A recent study conducted by Google shows that when forms are properly marked up with autocomplete attributes, and users leverage the autofill feature, they tend to complete the forms about 30% faster!

Now get out there and go make some money with the help of your new found Polymer skillz!

What you’ve learned

Learn More

Polymer

Forms