Nap Joseph N. Calub
Web Developer at Ingenuity Tech
Part-time instructor at AdDU
Open source enthusiast
ʕ ∗ •́ ڡ •̀ ∗ ʔ
a specification for a unified system of visual, motion, and interaction design that adapts across different devices.
It's modeled after tactile materials like paper and ink with fluid animation and lighting.
Polymer is the embodiment of material design for the web.
It is a library utilizing web components for building elements and applications.
"In a nutshell, they allow us to bundle markup and styles into custom HTML elements."
<body>
<video src="./foo.webm" controls></video>
</body>
<div id="slider">
<input checked="" type="radio" name="slider" id="slide1" selected="false">
<input type="radio" name="slider" id="slide2" selected="false">
<input type="radio" name="slider" id="slide3" selected="false">
<input type="radio" name="slider" id="slide4" selected="false">
<div id="slides">
<div id="overflow">
<div class="inner">
<img src="images//rock.jpg">
<img src="images/grooves.jpg">
<img src="images/arch.jpg">
<img src="images/sunset.jpg">
</div>
</div>
</div>
<label for="slide1"></label>
<label for="slide2"></label>
<label for="slide3"></label>
<label for="slide4"></label>
</div>
<img-slider>
<img src="images/sunset.jpg" alt="a dramatic sunset">
<img src="images/arch.jpg" alt="a rock arch">
<img src="images/grooves.jpg" alt="some neat grooves">
<img src="images/rock.jpg" alt="an interesting rock">
</img-slider>
Angular is a complete framework for building webapps, whereas Polymer is a library for creating Web Components.
Those components, however, can then be used to build a webapp.
<!-- Polyfill Web Components support for older browsers -->
<script src="components/webcomponentsjs/webcomponents.js"></script>
<!-- Import element -->
<link rel="import" href="google-map.html">
<!-- Use element -->
<google-map lat="37.790" long="-122.390"></google-map>
<!-- Define element -->
<polymer-element name="my-counter" attributes="counter">
<template>
<style> /*...*/ </style>
<div id="label"><content></content></div>
Value: <span id="counterVal">{{counter}}</span><br>
<button on-tap="{{increment}}">Increment</button>
</template>
<script>
Polymer({
counter: 0, // Default value
counterChanged: function() {
this.$.counterVal.classList.add('highlight');
},
increment: function() {
this.counter++;
}
});
</script>
</polymer-element>
<!-- Use element -->
<my-counter counter="10">Points</my-counter>
Let's create a basic Polymer app!
step-1/
step-2/
step-3/
finished/
components/
...
starter/
index.html
post-card.html
post-list.html
python -m SimpleHTTPServer
python -m http.server
<link rel="import"
href="../components/font-roboto/roboto.html">
<link rel="import"
href="../components/core-header-panel/core-header-panel.html">
<link rel="import"
href="../components/core-toolbar/core-toolbar.html">
<link rel="import"
href="../components/paper-tabs/paper-tabs.html">
index.html
<body unresolved>
<core-header-panel>
<core-toolbar>
</core-toolbar>
<!-- main page content will go here -->
</core-header-panel>
</body>
index.html
...
<core-toolbar>
<paper-tabs id="tabs" selected="all" self-end>
<paper-tab name="all">All</paper-tab>
<paper-tab name="favorites">Favorites</paper-tab>
</paper-tabs>
</core-toolbar>
...
index.html
html,body {
height: 100%;
margin: 0;
background-color: #E5E5E5;
font-family: 'RobotoDraft', sans-serif;
}
core-header-panel {
height: 100%;
overflow: auto;
-webkit-overflow-scrolling: touch;
}
core-toolbar {
background: #03a9f4;
color: white;
}
#tabs {
width: 100%;
margin: 0;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
text-transform: uppercase;
}
index.html
<script>
var tabs = document.querySelector('paper-tabs');
tabs.addEventListener('core-select', function() {
console.log("Selected: " + tabs.selected);
});
</script>
</body>
index.html
<link rel="import"
href="../components/polymer/polymer.html">
<link rel="import"
href="../components/core-icon-button/core-icon-button.html">
...
post-card.html
<polymer-element name="post-card">
<template>
<style>
:host {
display: block;
position: relative;
background-color: white;
padding: 20px;
width: 100%;
font-size: 1.2rem;
font-weight: 300;
}
.card-header {
margin-bottom: 10px;
}
</style>
<!-- CARD CONTENTS GO HERE -->
</template>
<script>
Polymer({});
</script>
</polymer-element>
post-card.html
...
<!-- CARD CONTENTS GO HERE -->
<div class="card-header" layout horizontal center>
<content select="img"></content>
<content select="h2"></content>
</div>
<content></content>
...
post-card.html
...
.card-header {
margin-bottom: 10px;
}
polyfill-next-selector { content: '.card-header h2'; }
.card-header ::content h2 {
margin: 0;
font-size: 1.8rem;
font-weight: 300;
}
polyfill-next-selector { content: '.card-header img'; }
.card-header ::content img {
width: 70px;
border-radius: 50%;
margin: 10px;
}
</style>
...
post-card.html
...
<link rel="import"
href="../components/paper-tabs/paper-tabs.html">
<link rel="import" href="post-card.html">
...
index.html
...
<core-toolbar>
<div class="container" layout vertical center>
<post-card>
<img width="70" height="70"
src="../images/avatar-07.svg">
<h2>Another Developer</h2>
<p>Hooray for shadow DOM!</p>
</post-card>
</div>
...
index.html
...
{
"uid": 1,
"text" : "Have you heard about the Web Components revolution?",
"username" : "Eric",
"avatar" : "../images/avatar-01.svg",
"favorite": false
},
{
"uid": 2,
"text" : "Loving this Polymer thing.",
"username" : "Rob",
"avatar" : "../images/avatar-02.svg",
"favorite": false
},
...
api/posts.json
...
<post-service id="service" posts="{{posts}}">
</post-service>
</template>
...
post-list.html
...
<post-service id="service" posts="{{posts}}">
</post-service>
<div layout vertical center>
<template repeat="{{post in posts}}">
<post-card>
<img src="{{post.avatar}}" width="70" height="70">
<h2>{{post.username}}</h2>
<p>{{post.text}}</p>
</post-card>
</template>
</div>
...
post-list.html
...
<link rel="import" href="../components/paper-tabs/paper-tabs.html">
<link rel="import" href="post-list.html">
<style>
...
index.html
...
<div class="container" layout vertical center>
<post-list show="all"></post-list>
</div>
...
index.html
<div class="card-header" layout horizontal center>
<content select="img"></content>
<content select="h2"></content>
</div>
<core-icon-button
id="favicon"
icon="favorite"
on-tap="{{favoriteTapped}}">
</core-icon-button>
<content></content>
post-card.html
<script>
Polymer({
publish: {
favorite: {
value: false,
reflect: true
}
},
favoriteTapped: function(event, detail, sender) {
this.favorite = !this.favorite;
this.fire('favorite-tap');
}
});
</script>
post-card.html
...
core-icon-button {
position: absolute;
top: 3px;
right: 3px;
color: #636363;
}
:host([favorite]) core-icon-button {
color: #da4336;
}
</style>
...
post-card.html
<script>
var tabs = document.querySelector('paper-tabs');
var list = document.querySelector('post-list');
tabs.addEventListener('core-select', function() {
list.show = tabs.selected;
});
</script>
index.html
...
<template repeat="{{post in posts}}">
<post-card
favorite="{{post.favorite}}"
on-favorite-tap="{{handleFavorite}}"
hidden?="{{show == 'favorites' && !post.favorite}}">
<img src="{{post.avatar}}" width="70" height="70">
<h2>{{post.username}}</h2>
<p>{{post.text}}</p>
</post-card>
</template>
...
post-list.html
...
<script>
Polymer({
handleFavorite: function(event, detail, sender) {
var post = sender.templateInstance.model.post;
this.$.service.setFavorite(post.uid, post.favorite);
}
});
</script>
...
post-list.html
</slides>
Nap Joseph N. Calub
Web Developer at Ingenuity Tech
Part-time instructor at AdDU
Open source enthusiast
ʕ ∗ •́ ڡ •̀ ∗ ʔ