PLAY
VIDEO
READ TIME: 5
Article

Polymer Web Components Tutorial

Author

/
DevOps DevOps

TOPICS:

/Software & Product
/Web / CMS / Replatforming
/Integrations & API

For all the front-end developers who just started to feel comfortable with last week's tools, it was recently announced at Google I/O that Google's Polymer version 1.0 is about to modernize your perception of the "widget." Known as Web Components, Polymer streamlines the process of implementing the Web Component standard and adds cross-browser support that makes Polymer just about production ready.To give a better example as to why Polymer and Web Components are so great, I'll take you through building a photo stream component using the API from our GIF photo booth app, Gifn, and explain each part as we go along.

A step-by-step tutorial

To start, create a new folder in the command line using:mkdir polymer_tutorialAnd then enter the folder using:cd polymer_tutorialTo install Polymer, we are going to use Bower, which is a package management tool for JavaScript. If you do not have Bower installed you can do so with:npm install -g bowerand then initialize Bower.bower initFrom there, follow the tool's prompts. If you're not sure how to answer a question, just push enter and use the default option. After Bower initializes, it should place a bower.json file in your directory. To add Polymer as a dependency, run this command:bower install --save Polymer/polymer#^1.0.0You should now have a bower_components/ folder in your directory that contains Polymer and its dependencies. Now, add two files to your root directory: an index.html file and a gifn-feed.html file that will contain your Polymer component. Your directory should now look something like this:polymer_tutorial/
bower_components/
bower.json
gifn-feed.html
index.html
First, let's open up the index.html file and set up our HTML to display the Polymer component. Here is all of the HTML needed to use a simple component.<!doctype html>
<html>
<head>
<title>Gifn Polymer</title>
<script src="bower_components/webcomponentsjs/webcomponents.min.js"></script>
<link rel="import" href="gifn-feed.html">
</head>
<body>
<gifn-feed event="prplhq"></gifn-feed>
</body>
</html>
There are three main parts to initializing the component in your index.html file. First you need to add the webcomponents library:<script src="bower_components/webcomponentsjs/webcomponents.min.js"></script>This library is required for all Polymer components and any custom components you create yourself. There is also a smaller webcomponents-lite.min.js library that can be used in replacement, if you are only building elements for browsers that currently support the Web Components API (Chrome 36+, for example). Next is the link tag importing our gifn-feed web component to be used.<link rel="import" href="gifn-feed.html">And then our actual web component in use:<gifn-feed event="prplhq"></gifn-feed>Everything looks pretty normal, except for the actual web component. The gifn-feed element is obviously not your normal HTML, and event="prplhq" is not an attribute you would expect, either. Fear not, this will all make sense once we start fleshing out the component.Let's get started. First, open up the gifn-feed.html file and add the required base Polymer element at the top of your file:<link rel="import" href="bower_components/polymer/polymer.html">One of the cool aspects about Polymer is that it allows you to import and extend elements in a very modular way. Outside of the required base polymer.html you could also import iron-ajax.html for easy Ajax calls or even a material design button with paper-button.html. You can check out some ready-to-use components Google has created.Since gifn-feed is going to be used in our HTML, we are going to initialize it as a DOM module like so:<dom-module id="gifn-feed">
</dom-module>
Now, for the fun part! Let's initialize the Polymer component with the base setup inside a script tag.<dom-module id="gifn-feed"> <script>
Polymer({
is: "gifn-feed", properties: {
event: String
}
});
</script></dom-module>
The "is:" attribute tells Polymer to look for an element with the tag gifn-feed and the "properties:" attribute tells Polymer to look for an "event" attribute that will have a string value.Our web component still does nothing, it's simply initialized. To add an action to the component, you can use one of the lifecycle callbacks, or in our case, use the "ready" callback for when our component's DOM has been initialized. Here is the gifn-feed component with the "ready" callback.<dom-module id="gifn-feed">
<script>
Polymer({
is: "gifn-feed", properties: {
event: String
}, ready: function() {
var self = this;
var xhr = new XMLHttpRequest();
var baseUrl = 'http://demo.gifn.it';
self.gifns = []; // Send an ajax request to get the gif data
xhr.open('GET', baseUrl + '/gif/' + self.event);
xhr.send();
xhr.onreadystatechange = function() { if(xhr.readyState == 4 && xhr.status == 200){
var gifns = [];
var response = JSON.parse(xhr.responseText); //Build out the urls for the 5 latest gifs
for(var i = 0; i < 5; i++){
var gifUrl = baseUrl+'/asset/'+self.event +'/'+ response.gifs[i].slug+'.thumb.gif';
gifns.push({ url: gifUrl });
} self.gifns = gifns;
}
}
}
});
</script></dom-module>
What we are doing in this ready function is making an Ajax request to the Gifn API to retrieve a list of GIF images. We then build out the URLs and place them in an array that is set to our Polymer object. Let me explain some of the more important aspects.var self = this;Although this is a common practice for dealing with internal scope in JavaScript functions, it's especially important to have access to the parent Polymer object so you can bind data to the view. Here's an example of it being used:xhr.open('GET', baseUrl + '/gif/' + self.event);This line is responsible for initializing the Ajax request to our API, but self.event is what makes it truly special. Remember the event="prplhq" attribute on our gifn-feed tag? It is now directly bound to our Polymer object for use in the JavaScript, HTML template, and even in our component's CSS. Here's another example:self.gifns = gifns;This time, instead of taking a value from our component's element attribute, we are creating an array of URLs inside the component that can then be used throughout. Polymer is flexible in that it allows for both one-way and two-way data binding.Now that we have our data set, let's create the view for our component. Above our script tag, add<template>
</template>
This is the base template tag required for all views. Inside of the template tag you can add HTML, other imported Polymer web components, and even some special helper elements used for if-statements and looping through data. Since we have an array of URLs, let's add a dom-repeat helper tag.<template>
<template is="dom-repeat" items="{{gifns}}">
<img src="{{item.url}}" />
</template>
</template>
Notice the {{gifns}} value in the items tag? This is how you directly access attributes bound to your Polymer object. So if you wanted to, you could also add a title for the event, like so:<h1>{{event}}</h1>In the case of the special dom-repeat element, it requires an "items" attribute that references an array value. The dom-repeat element will then loop through the array with each value being accessed using the "item" variable.After seeing the completed view, some of you may be wondering why I chose to make this string concatenation mess in the ready function.for(var i = 0; i < 5; i++){
var gifUrl = baseUrl + '/asset/' + self.event + '/' + response.gifs[i].slug + '.thumb.gif';
gifns.push({ url: gifUrl });
}
You all would probably agree this is the better and cleaner option.<template is="dom-repeat" items="{{gifns}}">
<img src="https://demo.gifn.it/asset/{{event}}/{{item.slug}}.thumb.gif" />
</template>
However, this is currently not possible, and is probably one of the biggest downfalls of the template builder in Polymer 1.0. String concatenation and whitespace with view variables is currently not supported in Polymer. Each element must take up the entire space of a view's element or the entire space of a string in an attribute.For example, this will work:<h1>Welcome <span>{{name}}</span></h1>but this will not:<h1>Welcome {{name}}</h1>To finalize the view, we'll add a touch of CSS to our component to make everything a little more fancy. Let's add this style block above our template tags.<style>
img {
display:inline-block;
}
</style>
Alright, maybe not that fancy, but I really hate floats. Another great feature of Polymer is that it keeps your component's CSS local, so you do not need to worry about conflicting CSS rules.And that's it! Here is the polymer component in its entirety.<link rel="import" href="bower_components/polymer/polymer.html"><dom-module id="gifn-feed">
<style>
img {
display:inline-block;
}
</style> <template>
<template is="dom-repeat" items="{{gifns}}">
<img src="{{item.url}}" />
</template>
</template> <script>
Polymer({
is: "gifn-feed",
properties: {
event: String
},
ready: function() { var self = this;
var xhr = new XMLHttpRequest();
var baseUrl = 'http://demo.gifn.it';
self.gifns = []; // Send an ajax request to get the gif data
xhr.open('GET', baseUrl + '/gif/' + self.event);
xhr.send();
xhr.onreadystatechange = function() {
if(xhr.readyState == 4 && xhr.status == 200){ var gifns = [];
var response = JSON.parse(xhr.responseText); //Build out the urls for the 5 latest gifs
for(var i = 0; i < 5; i++){
var gifUrl = baseUrl+'/asset/'+self.event+'/'+response.gifs[i].slug+'.thumb.gif';
gifns.push({ url: gifUrl });
} // Bind the response back to the {{gifns}} repeater
self.gifns = gifns;
}
}
}
});
</script>
</dom-module>
To view your Polymer component, you will need to host it through some type of server. This could be a local server, Vagrant box, MAMP, or one of my quick command line favoritespython -m SimpleHTTPServerEnjoy!A working demo can be seen at http://polymer.gifn.it, and all of the source code can be viewed on my GitHub at https://github.com/adamboerema/polymertutorial.For further documentation, check out:

  • https://www.polymer-project.org/1.0/
  • http://webcomponents.org/

How Brands Can Leverage AI to Enhance Customer Experience

Reframing the Web: Your Site Isn’t a Destination. It’s an Experience Platform.

Team Highlight: Cassie Tangney

Outlandish Optimism at PRPL | International Design Day 2025

Unlocking the Power of Content Organization: Insights for Museums and Beyond

Team Highlight: Jeff Katipunan

PRPL and Museums: A Partnership Built on Creativity and Impact

Team Highlight: Maria Szlosek

Team Highlight: Vic Cao

Team Highlight: Jenn Hunter

Driving Innovation in Design Management: Strategies for Fostering Creativity

Team Highlight: Anibal Cruz

Mastering Leadership with SLANT: A Principle for Effective Engagement By Bobby Jones

Breaking Boundaries With Augmented Reality

Navigating the Replatforming Process: A Comprehensive Guide for a Smooth Transition

Team Highlight: April Domingo

Team Highlight: Chris Sell

Agency Partnerships: What’s In It For You

Upgrading from Drupal 9 to Drupal 10: A Step-By-Step Guide

Team Highlight: Francesca Parker

Navigating the Replatforming Process: A Comprehensive Guide for a Smooth Transition

Purple, Rock, Scissors Wins Web3 Awards, Including Two Golds

Purple, Rock, Scissors Wins Six ADDY® Awards, including Best of Show

Transforming User Experience through Augmented Reality

Purple, Rock, Scissors Tops Orlando Business Journal's Book of Lists

Transforming the Patient Experience: Purple, Rock, Scissors' Collaborative Partnership With AdventHealth

State of the Art: How AI is Influencing Design

8 Ways to Increase Museum Visits with Digital Experiences

Functional vs. Class-Based React

10 Components Your Museum Website Needs to Succeed

Staff Augmentation: Utilizing Digital Creative Agencies for Your Business Needs

Technical Insights: Integrating Your Health App with Epic EHR/EMR Systems

Remote work? Hybrid ? We prefer flexible.

Optimization Primed: How AI is Making Businesses More Efficient

Fit to Print: How AI is Improving Business Writing

Best Museum Websites to Inspire Your Next Redesign

PRPL Summit Weekend

Cam's Tips for Working Remote

Google Update: Core Web Vitals

CX Essentials: What the Customer Experience Can Teach You About Being a Better Brand

PRPL Playlist: Creative as Folk

Google Update: Mobile-First-Indexing for the Whole Web, and What it Means for Your Website & Business

Student Design Society: Apply for Our Summer 2019 Internship

PRPL Playlist: Hits from the Crypt

PRPL Playlist: Back 2 School

PRPL Playlist: 1nn0vate

Scientific Storytelling at the Field Museum

What To Do When a Project Is on Hold

Hard Rock + PRPL

What Organization Means to a Creative Person

PRPL Playlist: Artificial Inchilligence

PRPL Playlist: BBQ Bangers

Vote PRPL in SXSW's PanelPicker!

A Comprehensive Beginner’s Guide to Automating with Ansible

Launched: Lux Capital

We've Moved to Medium!

Spotlight: Chris Reath

Content Before Design: The Fall of Lorem Ipsum

PRPL Playlist

3-Pointers: Project Manager Advice

Spotlight: Rad Kalaf

Launched: LMG

What the Internet's New TLS 1.2 Encryption Standards Mean for You. Yes, You.

Let’s Talk About SaaS, Baby.

NASA’s IDEAS Project Update: Phase 1

Thinking and Designing with Components

3-Pointers: Stellar Style Guides

Launched: Stetson University

Put on Those Beer Goggles!

Polymer Web Components Tutorial

Battle of the Jams

What’s My Title, Again? A Case for Generalists in the Web Industry

3-Pointers: Boost Tweet Engagement

Myers Briggs for Businesses

More iBeacons, Please!

Launched: 3Cinteractive

Spotlight: Katie Bartlett

Mo' Data, Less Problems: Finding Value in Big Data

What the Heck is an Agency Partner?

Briefs: Renee on Why Devs Are Cranky

How We Scrapped Time Sheets

5 Reasons Why the Office Phone is Dead

Launched: Adventist University of Health Sciences

Why Changing Careers is Like Changing Your Pants

How to Build an App Using Meteor JS

Spotlight: Adam Bullinger

Experimenting with Meteor Development

Webinar: A Field Guide to Interaction Design

Landed: NASA Partnership

Gifn: Rise of the GIF Photobooth

Briefs: Mike on Value-based Billing & Profit

iSummit Conference & Ticket Giveaway

Briefs: Adam & Renee on Magento

Chasing Perfect Weather with Mullen & CSX

Developing With Vagrant Flavors

Need Some Space? Book Ours.

Spotlight: Alex King

Designer Merch Collection

10 Reasons to Offer Flexible Work Hours

Google I/O Fanboy Duel

Close

TEAM MEMBER

ABOUT

DevOps DevOps

ABOUT

Test title

Description 6

Corsair keel rope's end list Pieces of Eight lateen sail Arr gabion Yellow Jack belay. Arr rum provost lookout Barbary Coast Jack Ketch marooned list long boat belaying pin. Hands red ensign Brethren of the Coast deadlights yawl mizzenmast Sink me handsomely broadside capstan. Chase guns loot Nelsons folly Pieces of Eight Brethren of the Coast warp pinnace squiffy boom coxswain. Heave to Jolly Roger bilge water hardtack lateen sail Spanish Main quarterdeck trysail crow's nest Blimey. Pressgang fathom American Main Barbary Coast run a rig aye Sink me lad Jack Tar belay.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.