Home Start Get started Quick tour of Polymer Install the Release Candidate Polymer Feature overview What's new About Polymer 2.0 Upgrade guide Hybrid elements Release notes Custom elements Custom element concepts Define an element Declare properties Shadow DOM & styling Shadow DOM concepts DOM templating Style shadow DOM Custom CSS properties Events Handle and fire events Gesture events Data system Data system concepts Work with object and array data Observers and computed properties Data binding Helper elements Tools Tools overview Polymer CLI Document your elements Test your elements Optimize for production Advanced tools Services polymer.json specification Node support Resources Browser compatibility Glossary API Reference API Reference App Toolbox What's in the box? Using the Toolbox App templates Responsive app layout Routing Localization App storage Service worker Serve your app Case study Shop News Blog Community Get started Quick tour of Polymer Install the Release Candidate

Polymer makes it simple to create web components, declaratively.

Custom elements can leverage Polymer's special features to reduce boilerplate and make it even easier to build complex, interactive elements:

  • Registering elements
  • Lifecycle callbacks
  • Property observation
  • Shadow DOM template
  • Data binding

In this section you can take a quick tour of the Polymer library, without installing anything. Click the Edit on Plunker button to open any of the samples in an interactive sandbox.

Tap the buttons following each feature to learn more.

To register a new element, create an ES6 class that extends Polymer.Element, then call the customElements.define method, which registers a new element with the browser. Registering an element associates an element name with a class, so you can add properties and methods to your custom element. The custom element's name must start with an ASCII letter and contain a dash (-).

<link rel="import"  href="https://polygit.org/polymer+2.0.0-rc.2/components/polymer/polymer-element.html">

<script>
  // Define the class for a new element called custom-element
  class CustomElement extends Polymer.Element {
    static get is() { return "custom-element"; }
    constructor() {
        super();
        this.textContent = "I'm a custom-element.";
      }
  }
  // Register the new element with the browser
  customElements.define(CustomElement.is, CustomElement);
</script>
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://polygit.org/webcomponentsjs+1.0.0-rc.5/components/webcomponentsjs/webcomponents-loader.js"></script>
    <link rel="import" href="custom-element.html">
  </head>
  <body>
    <custom-element></custom-element>
  </body>
</html>

This sample uses a lifecycle callback to add contents to the <custom-element> when it's initialized. When a custom element finishes its initialization, the ready lifecycle callback is called. You can use the ready callback for one-time initialization work after the element is created.

Learn more: element registration

Learn more: lifecycle callbacks

Many elements include some internal DOM nodes to implement the element's UI and behavior. You can use Polymer's DOM templating to create a shadow DOM tree for your element.

<link rel="import"  href="https://polygit.org/polymer+2.0.0-rc.2/components/polymer/polymer-element.html">

<dom-module id="dom-element">

  <template>
    <p>I'm a DOM element. This is my local DOM!</p>
  </template>

  <script>
    class DomElement extends Polymer.Element {
      static get is() { return "dom-element"; }
    }
    customElements.define(DomElement.is, DomElement);
  </script>

</dom-module>
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://polygit.org/webcomponentsjs+1.0.0-rc.5/components/webcomponentsjs/webcomponents-loader.js"></script>
    <link rel="import" href="dom-element.html">
  </head>
  <body>
    <dom-element></dom-element>
  </body>
</html>

Shadow DOM is encapsulated inside the element.

Learn more: DOM templating

Shadow DOM lets you control composition. The element's children can be distributed so they render as if they were inserted into the shadow DOM tree.

This example creates a simple tag that decorates an image by wrapping it with a styled <div> tag.

<link rel="import"  href="https://polygit.org/polymer+2.0.0-rc.2/components/polymer/polymer-element.html">

<dom-module id="picture-frame">

  <template>
    <!-- scoped CSS for this element -->
    <style>
      div {
        display: inline-block;
        background-color: #ccc;
        border-radius: 8px;
        padding: 4px;
      }
    </style>
    <div>
      <!-- any children are rendered here -->
      <slot></slot>
    </div>
  </template>

  <script>
    class PictureFrame extends Polymer.Element {
      static get is() { return "picture-frame"; }
    }
    customElements.define(PictureFrame.is, PictureFrame);
  </script>

</dom-module>
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://polygit.org/webcomponentsjs+1.0.0-rc.5/components/webcomponentsjs/webcomponents-loader.js"></script>
    <link rel="import" href="picture-frame.html">
  </head>
  <body>
    <picture-frame>
      <img src="https://www.polymer-project.org/images/logos/p-logo-32.png">
    </picture-frame>
  </body>
</html>

Note: The CSS styles defined inside the <dom-module> are scoped to the element's shadow DOM. So the div rule here only affects <div> tags inside <picture-frame>.

Learn more: Composition & distribution

Of course, it's not enough to have static shadow DOM. You usually want to have your element update its shadow DOM dynamically.

Data binding is a great way to quickly propagate changes in your element and reduce boilerplate code. You can bind properties in your component using the "double-mustache" syntax ({{}}). The {{}} is replaced by the value of the property referenced between the brackets.

<!-- import polymer-element -->
<link rel="import"  href="https://polygit.org/polymer+2.0.0-rc.2/components/polymer/polymer-element.html">

<dom-module id="name-tag">
  <template>
    <!-- bind to the "owner" property -->
    This is <b>{{owner}}</b>'s name-tag element.
  </template>
  
  <script>
    class NameTag extends Polymer.Element {
      static get is() { return "name-tag"; }
      
      // set this element's owner property
      constructor() {
        super();
        this.owner = "Daniel";
      }
    }
    
    customElements.define(NameTag.is, NameTag);
  </script>
</dom-module>
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://polygit.org/webcomponentsjs+1.0.0-rc.5/components/webcomponentsjs/webcomponents-loader.js"></script>
    <link rel="import" href="name-tag.html">
  </head>
  <body>
    <name-tag></name-tag>
  </body>
</html>

Learn more: data binding

Properties are an important part of an element's public API. Polymer declared properties support a number of common patterns for properties—setting default values, configuring properties from markup, observing property changes, and more.

The following example declares the owner property from the last example. It also shows configuring the owner property from markup in index.html.

<link rel="import"  href="https://polygit.org/polymer+2.0.0-rc.2/components/polymer/polymer-element.html">

<dom-module id="configurable-name-tag">

  <template>
    <!-- bind to the "owner" property -->
    This is <b>[[owner]]</b>'s name-tag element.
  </template>

  <script>
    class ConfigurableNameTag extends Polymer.Element {
      static get is() { return "configurable-name-tag"; }
      // configure owner property
      constructor() {
        super();
        this.owner = "Daniel";
      }
    }
    customElements.define(ConfigurableNameTag.is, ConfigurableNameTag);
  </script>

</dom-module>
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://polygit.org/webcomponentsjs+1.0.0-rc.5/components/webcomponentsjs/webcomponents-loader.js"></script>
    <link rel="import" href="configurable-name-tag.html">
  </head>
  <body>
    <!-- configure a property from markup by setting
         the corresponding attribute                 -->
    <configurable-name-tag owner="Scott"></configurable-name-tag>
  </body>
</html>

Learn more: declared properties

In addition to text content, you can bind to an element's properties (using property-name="[[binding]]"). Polymer properties can optionally support two-way binding, using curly braces (property-name="{{binding}}").

This example uses two-way binding: binding the value of a custom input element (iron-input) to the element's owner property, so it's updated as the user types.

<link rel="import"  href="https://polygit.org/polymer+2.0.0-rc.2/iron-input+polymerelements+:2.0-preview/shadycss+webcomponents+1.0.0-rc.2/components/polymer/polymer-element.html">
<!-- import the iron-input element -->
<link rel="import"  href="https://polygit.org/polymer+2.0.0-rc.2/iron-input+polymerelements+:2.0-preview/shadycss+webcomponents+1.0.0-rc.2/components/iron-input/iron-input.html">

<dom-module id="editable-name-tag">

  <template>
    <!-- bind to the "owner" property -->
    <p>This is <b>[[owner]]</b>'s name-tag element.</p>
    
    <!-- iron-input exposes a two-way bindable input value -->
    <iron-input bind-value="{{owner}}">
      <input is="iron-input" placeholder="Your name here...">
    </iron-input>
  </template>

  <script>
    class EditableNameTag extends Polymer.Element {
      static get is() { return "editable-name-tag"; }
      
      // configure the owner property
      static get properties() {
        return {
          owner: {
            type: String,
            value: 'Daniel'
          }
        };
      }
      
    }
    customElements.define(EditableNameTag.is, EditableNameTag);
  </script>

</dom-module>
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://polygit.org/webcomponentsjs+1.0.0-rc.5/components/webcomponentsjs/webcomponents-loader.js"></script>
    <link rel="import" href="editable-name-tag.html">
  </head>
  <body>
    <editable-name-tag></editable-name-tag>
  </body>
</html>

Note: The <iron-input> element wraps a native <input> element and provides two-way data binding and input validation.

The template repeater (dom-repeat) is a specialized template that binds to an array. It creates one instance of the template's contents for each item in the array.

<!-- import polymer-element -->
<link rel="import"  href="https://polygit.org/polymer+2.0.0-rc.2/components/polymer/polymer-element.html">
<link rel="import"  href="https://polygit.org/polymer+2.0.0-rc.2/components/polymer/lib/elements/dom-repeat.html">

<dom-module id="employee-list">
  <template>
    <div> Employee list: </div>
    <p></p>
    <template is="dom-repeat" items="{{employees}}">
        <div>First name: <span>{{item.first}}</span></div>
        <div>Last name: <span>{{item.last}}</span></div>
        <p></p>
    </template>
  </template>
  <script>
    class EmployeeList extends Polymer.Element {
      static get is() { return "employee-list"; }
      
      // set this element's employees property
      constructor() {
        super();
        this.employees = [
          {first: 'Bob', last: 'Li'},
          {first: 'Ayesha', last: 'Johnson'},
          {first: 'Fatma', last: 'Kumari'},
          {first: 'Tony', last: 'Morelli'}
        ]; 
      }
    }
  customElements.define(EmployeeList.is, EmployeeList);
  </script>

</dom-module>
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://polygit.org/webcomponentsjs+1.0.0-rc.5/components/webcomponentsjs/webcomponents-loader.js"></script>
    <link rel="import" href="employee-list.html">
  </head>
  <body>
    <employee-list></employee-list>
  </body>
</html>

Now that you understand these fundamental Polymer concepts, you can build an app with App Toolbox or see a feature overview of the Polymer library.