polymer polytechnic george town 2014
TRANSCRIPT
George Town, November 2014
+Vin Lim @vinlim
#itshackademic @polymer
Agenda Overview Components Join the revolution
Web Components: Overview
What problems are we solving?
@polymer #itshackademic
http://drbl.in/esYL
Building UI tabs should be easy!
@polymer #itshackademic
@polymer #itshackademic
@polymer #itshackademic
@polymer #itshackademic
@polymer #itshackademic
<paper-tabs>
<paper-tab>KNOWLEDGE</paper-tab>
<paper-tab>HISTORY</paper-tab>
<paper-tab>FOOD</paper-tab>
</paper-tabs>
Less Code. Less confusion. Web Components
What are Web Components?
Custom Elements define new HTML/DOM elements
<paper-tabs selected=“1”>
<paper-tab>Tab 1</paper-tab>
<paper-tab>Tab 2</paper-tab>
<paper-tab>Tab 3</paper-tab>
</paper-tabs>
declarative, readable
meaningful HTML
common way to extend → reusable
Custom Elements define new HTML
@polymer #itshackademic
declarative, readable
meaningful HTML
common way to extend → reusable
Custom Elements define new HTML
var tabs = document.querySelector('paper-tabs');
tabs.addEventListener('core-activate', function() {
console.log(this.selected);
});
@polymer #itshackademic
Templates native client-side templating
<template>
<div class=“comment”>
<img src=“image.png”>
</div>
<script>...</script>
</template>
use DOM to scaffold DOM → no XSS
content is inert until cloned/used
doc fragment → not part of the page
HTML Templates native client-side templates
parsed, not rendered
@polymer #itshackademic
Shadow DOM DOM/CSS scoping
<video src=“foo.webm” controls></video>
@polymer #itshackademic
<video src=“foo.webm” controls></video>
Actually Shadow DOM
@polymer #itshackademic
<video src=“foo.webm” controls></video>
HTML Imports loading web components
@polymer #itshackademic
@polymer #itshackademic
Vulcanize
$ vulcanize -o build.html index.html \ --csp --strip
npm install -g vulcanize
grunt-vulcanize
gulp-vulcanize
Custom Elements Create new HTML elements and extend existing ones
Templates Native templating in the browser
Shadow DOM Scoped CSS!!! + encapsulated markup
HTML Imports Load custom element definitions and resources
@polymer #itshackademic
@polymer #itshackademic
@polymer #itshackademic
@polymer #itshackademic
Browser support Summer 2014
Polyfills Web Components with platform.js *
* soon to be called webcomponents.js
Adds syntactic “sugar” with polymer.js
Browser support Summer 2014 (without Polymer)
Browser support Summer 2014 (with Polymer)
Sugaring: Custom Elements
vanilla
polymer <polymer-element name=“paper-tabs”> … </polymer-element>
usage
<paper-tabs>…</paper-tabs> // document.createElement(‘paper-tabs’);
document.registerElement(‘paper-tabs’, {
prototype: Object.create(HTMLElement.prototype)
});
@polymer #itshackademic
document.registerElement(‘paper-tabs’, {
prototype: Object.create(HTMLElement.prototype)
});
vanilla
polymer <polymer-element name=“paper-tabs”> … </polymer-element>
usage
<paper-tabs>…</paper-tabs> // document.createElement(‘paper-tabs’);
@polymer #itshackademic
vanilla
polymer <polymer-element name=“paper-tabs”> … </polymer-element>
usage
<paper-tabs>…</paper-tabs> // document.createElement(‘paper-tabs’);
document.registerElement(‘paper-tabs’, {
prototype: Object.create(HTMLElement.prototype)
});
@polymer #itshackademic
vanilla
polymer <polymer-element name=“paper-tabs”> … </polymer-element>
usage
<paper-tabs>…</paper-tabs> // document.createElement(‘paper-tabs’);
document.registerElement(‘paper-tabs’, {
prototype: Object.create(HTMLElement.prototype)
});
@polymer #itshackademic
vanilla
polymer <polymer-element name=“super-button” extends=“button”> … </polymer-element>
usage
<button is=“super-button”>…</button> // document.createElement(‘button’, ‘super-button’);
document.registerElement(‘super-button’, {
prototype: Object.create(HTMLButtonElement.prototype),
extends: ‘button’
});
@polymer #itshackademic
vanilla
polymer <polymer-element name=“super-button” extends=“button”> … </polymer-element>
usage
<button is=“super-button”>…</button> // document.createElement(‘button’, ‘super-button’);
document.registerElement(‘super-button’, {
prototype: Object.create(HTMLButtonElement.prototype),
extends: ‘button’
});
@polymer #itshackademic
vanilla
polymer <polymer-element name=“super-button” extends=“button”> … </polymer-element>
usage
<button is=“super-button”>…</button> // document.createElement(‘button’, ‘super-button’);
document.registerElement(‘super-button’, {
prototype: Object.create(HTMLButtonElement.prototype),
extends: ‘button’
});
@polymer #itshackademic
vanilla
polymer <polymer-element name=“super-button” extends=“button”> … </polymer-element>
usage
<button is=“super-button”>…</button> // document.createElement(‘button’, ‘super-button’);
document.registerElement(‘super-button’, {
prototype: Object.create(HTMLButtonElement.prototype),
extends: ‘button’
});
@polymer #itshackademic
Sugaring: Templates
vanilla
polymer
<polymer-element name=“user-list” noscript> <template> <ul> <template repeat=“{{user, i in users}}”> <li>{{user.name}}</li> </template> </ul> </template> </polymer-element>
<template> … </template>
@polymer #itshackademic
vanilla
polymer
<polymer-element name=“user-list” noscript> <template> <ul> <template repeat=“{{user, i in users}}”> <li>{{user.name}}</li> </template> </ul> </template> </polymer-element>
<template> … </template>
@polymer #itshackademic
vanilla
polymer
<polymer-element name=“user-list” noscript> <template> <ul> <template repeat=“{{user, i in users}}”> <li>{{user.name}}</li> </template> </ul> </template> </polymer-element>
<template> … </template>
@polymer #itshackademic
Sugaring: Shadow DOM
var shadow = el.createShadowRoot();
shadow.innerHTML = “<style>h2 { color: red; }</style>” +
“<h2>I’m a profile-card</h2>”;
vanilla
<polymer-element name=“profile-card” noscript>
<template>
<link rel=“stylesheet” href=“styles.css”>
<h2>I’m a profile-card</h2>
</template>
</polymer-element>
polymer
@polymer #itshackademic
var shadow = el.createShadowRoot();
shadow.innerHTML = “<style>h2 { color: red; }</style>” +
“<h2>I’m a profile-card</h2>”;
vanilla
<polymer-element name=“profile-card” noscript>
<template>
<link rel=“stylesheet” href=“styles.css”>
<h2>I’m a profile-card</h2>
</template>
</polymer-element>
polymer
@polymer #itshackademic
var shadow = el.createShadowRoot();
shadow.innerHTML = “<style>h2 { color: red; }</style>” +
“<h2>I’m a profile-card</h2>”;
vanilla
<polymer-element name=“profile-card” noscript>
<template>
<link rel=“stylesheet” href=“styles.css”>
<h2>I’m a profile-card</h2>
</template>
</polymer-element>
polymer
@polymer #itshackademic
Components
<ul> <p>
<h1>
<menu-button> <page-scaffold>
<animated-pages>
What if we designed HTML for the mobile web?
<core-icon>
<paper-fab>
<core-drawer-panel>
<core-field>
http://bit.ly/1jkTo5c
core-elements
Image: http://bit.ly/1mZjnTu
<core-toolbar> A basic container for controls like tabs or buttons
MY APP
@polymer #itshackademic
<link rel=“import”
href=“core-toolbar.html”>
<core-toolbar> A basic container for controls like tabs or buttons
MY APP
@polymer #itshackademic
<core-toolbar>
<div>MY APP</div>
</core-toolbar>
<link rel=“import”
href=“core-toolbar.html”>
<core-toolbar> A basic container for controls like tabs or buttons
MY APP
@polymer #itshackademic
<core-toolbar>
<core-icon-button icon=“menu”>
</core-icon-button>
<div>MY APP</div>
</core-toolbar>
<link rel=“import”
href=“core-toolbar.html”>
<core-toolbar> A basic container for controls like tabs or buttons
MY APP
@polymer #itshackademic
A simple container with a header section and a content section
<core-header-panel>
MY APP
<core-header-panel flex>
<core-toolbar>
<core-icon-button icon=“menu">
</core-icon-button>
<div>MY APP</div>
</core-toolbar>
<div class=“content”>…</div>
</core-header-panel>
A simple container with a header section and a content section
<core-header-panel>
MY APP
<core-header-panel flex>
<core-toolbar>
<core-icon-button icon=“menu">
</core-icon-button>
<div>MY APP</div>
</core-toolbar>
<div class=“content”>…</div>
</core-header-panel>
A simple container with a header section and a content section
<core-header-panel>
MY APP
<core-header-panel flex>
<core-toolbar>
<core-icon-button icon=“menu">
</core-icon-button>
<div>MY APP</div>
</core-toolbar>
<div class=“content”>…</div>
</core-header-panel>
A simple container with a header section and a content section
<core-header-panel>
<core-header-panel flex>
<core-toolbar>
<core-icon-button icon=“menu">
</core-icon-button>
<div>MY APP</div>
</core-toolbar>
<div class=“content”>…</div>
</core-header-panel>
MY APP
<core-header-panel mode=“scroll" flex>
<core-toolbar>
<core-icon-button icon=“menu">
</core-icon-button>
<div>MY APP</div>
</core-toolbar>
<div class=“content”>…</div>
</core-header-panel>
<core-header-panel>
Toolbar will scroll with the page
A responsive container that combines a left- or right-side drawer panel and a main content area.
<core-drawer-panel>
<core-drawer-panel>
<div drawer> Drawer panel... </div>
<div main> Main panel... </div>
</core-drawer-panel>
<core-drawer-panel>
<div drawer> Drawer panel... </div>
<div main> Main panel... </div>
</core-drawer-panel>
A responsive container that combines a left- or right-side drawer panel and a main content area.
<core-drawer-panel>
<core-drawer-panel>
<div drawer> Drawer panel... </div>
<div main> Main panel... </div>
</core-drawer-panel>
A responsive container that combines a left- or right-side drawer panel and a main content area.
<core-drawer-panel>
paper-elements
<paper-input floatinglabel
label="Type only numbers... (floating)"
validate="^[0-9]*$"
error="Input is not a number!">
</paper-input>
@polymer #itshackademic
<paper-checkbox></paper-checkbox>
<div class=“card”>
<img src=“science.svg”>
<paper-ripple fit></paper-ripple>
</div>
A reactive ink effect for indicating touch and mouse actions
<paper-ripple>
<div class=“card”>
<paper-shadow z=“5” animated>
</paper-shadow>
</div>
A dynamic shadow for conveying z-depth and spatial relationships
<paper-shadow>
@polymer #itshackademic
Styling
<paper-slider min=“0” max=“100”>
</paper-slider>
allows you to style nodes internal to an element’s shadow dom
::shadow
@polymer #itshackademic
allows you to style nodes internal to an element’s shadow dom
::shadow
paper-slider::shadow #sliderKnobInner {
background-color: #f4b400;
}
<paper-slider min=“0” max=“100”>
</paper-slider>
@polymer #itshackademic
html /deep/ paper-ripple {
background-color: #E91E63;
}
styles will pierce all shadow boundaries
/deep/
@polymer #itshackademic
With ::shadow and /deep/ you can apply sitewide themes
source: ebidel.github.io/material-playground
polymer-project.org/apps/topeka/
polymer-project.org
We’re not alone
Mozilla Brick
<brick-appbar>
<brick-deck>
<brick-tabbar>
<core-icon>
<x-instagram>
(not shown)
Web Components can work together
Not just browser makers
<app-router> github.com/erikringsmuth/app-router
my-site.com/order/:id
<app-router>
<!-- matches an exact path -->
<app-route path="/home" import="/pages/home-page.html"></app-route>
<!-- matches using a path variable -->
<app-route path="/order/:id" import=“/pages/order-page.html"></app-route>
</app-router>
<page-er> github.com/addyosmani/page-er
<page-er perpage="5" previous=“<< Previous" next=“Next >>"></page-er>
var pager = document.querySelector("page-er");
document.addEventListener("polymer-ready", function() {
pager.data = model.items;
});
<ajax-form> github.com/garstasio/ajax-form
Full Name
Country City
Join newsletter
<form is="ajax-form" action="my/form/handler">
<label>Full Name
<input type="text" name=“full_name">
</label>
…
</form>
√
Apps
polymer-project.org
chromestatus.com
polymer-project.org/tools/designer/
github.com/ForceDotComLabs/mobile-ui-elements github.com/ForceDotComLabs
APIs
APIs (as elements)
I want to add a marker to a Google map.
@polymer #itshackademic
<style>
#map {
height: 400px;
}
</style>
<div id="map"></div>
<script src=“http://maps.googleapis.com/maps/api/js?callback=mapReady">
</script>
<script>
var marker = null;
function getCurrentLocation(callback) {
navigator.geolocation.watchPosition(callback);
}
function addMarker(opts, info) {
var marker = new google.maps.Marker(opts);
var infoWindow = new google.maps.InfoWindow({content: info});
google.maps.event.addListener(marker, 'click', function() {
infoWindow.open(opts.map, marker);
});
return marker;
}
function mapReady() {
var container = document.querySelector('#map');
var map = new google.maps.Map(container, {
zoom: 14, disableDefaultUI: true
});
getCurrentLocation(function(pos) {
var current = new google.maps.LatLng(pos.coords.latitude,
pos.coords.longitude);
map.setCenter(current);
// Re-position marker or create new one.
if (marker) {
marker.setPosition(map.getCenter());
} else {
marker = addMarker({
position: current, map: map, title: 'Your location'
}, '<b>Your location</b>');
}
});
}
</script>
So much code for one map marker!
@polymer #itshackademic
@polymer #itshackademic
googlewebcomponents.github.io github.com/GoogleWebComponents
youtube.com/watch?v=eORqFaf_QzM
Join the revolution
Learn
polymer-project.org
goo.gl/Ji3WdW
Build
YO POLYMER npm install -g generator-polymer
Start with <seed-element> github.com/PolymerLabs/seed-element
youtube.com/watch?v=2toYLLcoY14
Share!
customelements.io
{
"name": "my-element",
"version": "0.0.0",
"description": "My awesome Custom Element",
"license": "MIT",
"keywords": [
"web-components"
],
"ignore": [
"**/.*",
"node_modules",
"bower_components"
]
}
bower.json
@polymer #itshackademic
EXPLORE
<thank-you>
+Vin Lim @vinlim