about:me
Eric Bidelman
Staff Developer Programs Engineer,
"Using the HTML5 Filesystem API" - O'Reilly
Polymer
Polymer is a new type of library for the web, built on top of Web Components, and designed to leverage the evolving web platform … on modern browsers.
polymer-project.org
Soooo Polymer is...
Polyfills?
A framework?
UI widgets?

It looks like you're building a web page on the internet!
<select> <option>Small</option> <option>Medium</option> <option>Large</option> </select>

I give my children a default UI!
<select id="schwag"> ... <option disabled>Medium</option> <option disabled>Large</option> <option selected>XX-large</option> </select>

Elements are configured using attributes, not script.
<select size="4" multiple> <option>Do</option> <option>Re</option> <option>Mi</option> ... </select>

Attributes even change how users interact with me
<select> <optgroup label="German Cars"> <option>Mercedes</option> <option>Audi</option> </optgroup> ... </select>

Attributes can effect my UI.
<select> <option>Small</option><li>Medium</li><option>Large</option> </select>

I'm picky! I only
allowaccept certain elements as children.
<form> <select name="size"> <option value="s">Small</option> <option value="m">Medium</option> <option value="l">Large</option> </select> </form>

In other contexts, I take on additional responsibilities.

My DOM exposes properties/methods to JS that don't make sense as markup. I also fire events when interesting things happen.
Where are we today?
Dead?
<gangnam-style></gangnam-style>
<photo-booth></photo-booth>
<button is="mega-button">Mega button</button>
Gut check: building a tab component on the web...





Pile on loads of JS
Our markup is atrocious
What a nightmare!
This is how we build web apps!
We're far away from where we started
Markup can be meaningful again
<hangout-module> <hangout-chat from="Paul, Addy" profile="118075919496626375791"> <hangout-discussion> <hangout-message from="Paul" profile="profile.png" datetime="2013-07-17T12:02"> <p>Feelin' this Web Components thing.</p> <p>Heard of it?</p> </hangout-message> <hangout-message from="Addy" datetime="2013-07-17T12:12">...</hangout-message> <hangout-message>...</hangout-message> ... </hangout-discussion> </hangout-chat> <hangout-chat></hangout-chat> </hangout-module>
Polymer
Spoiler
alert
Templates





HTML Imports





Custom Elements





Shadow DOM





What is it?
Shadow DOM, Custom Elements, HTML Imports, Pointer Events...
expresses opinionated way to use web component concepts together
comprehensive set (in progress)
Philosophy & Goals
Everything as an element
HTML is cool. DOM feels good.
Eliminate boilerplate
Remove tediousness of building web component-based apps
Utilize the modern web platform
Support modern browsers
Polymer
Utilize the modern web platform.
1st-class support for spec features...
Lifecycle callbacks
Support for the lifecycle methods...but shorter names!
Polymer('my-input', { ready: function() { ... }, // Polymer addition for when element is fully initialized. created: function() { ... }, enteredView: function() { ... }, leftView: function() { ... }, attributeChanged: function(attrName, oldVal, newVal) { ... } });
Use cases:
- perform setup/teardown work
- notification when element is inserted/removed from page
Insertion points
define an internal structure
<polymer-element name="my-tabs" noscript> <template> <style>...</style> <header> <content select="h2"></content> </header> <content select="section"></content> </template> </polymer-element>
<link rel="import" href="my-tabs.html"> <my-tabs> <h2>Title</h2> <section>content</section> <h2>Title 2</h2> ... </my-tabs>

Scoped styling
Support for styling features (scoped styles, applyAuthorStyles
, etc.)
<polymer-element name="my-element"> <template> <style>...</style> <!-- Styles are scoped to the element --> </template> <script> Polymer('my-element', { applyAuthorStyles: true, resetStyleInheritance: false }); </script> </polymer-element>
- Polymer attempts to polyfill most Shadow DOM style features
Bundle & deliver CSS/HTML/JS
Reuse others' components:
<link rel="import" href="x-toolbar.html"> <link rel="import" href="menu-item.html"> <polymer-element name="awesome-menu"> <template> <x-toolbar responsive> <menu-item src="images/do.png" selected>Do</menu-item> <menu-item src="images/re.png">Re</menu-item> <menu-item src="images/mi.png">Mi</menu-item> <x-toolbar> </template> ... </polymer-element>
<link rel="import" href="awesome-menu.html"> <awesome-menu></awesome-menu>
Polymer
polymer-project.org/docs/elements/
Everything is an element.
Everything is an element
AJAX...using DOM
<script src="polymer.min.js"></script> <link rel="import" href="polymer-ajax.html">
<polymer-ajax url="http://gdata.youtube.com/feeds/api/videos/" params='{"alt":"json"}'></polymer-ajax>
var ajax = document.querySelector('polymer-ajax'); ajax.addEventListener('polymer-response', function(e) { console.log(JSON.parse(this.response).feed.entry); }); ajax.go();
Real-world examples of polymer-ajax
chromestatus.com/features
polymer-project.org/build/
Everything is an element
read files...using DOM
<script src="polymer.min.js"></script> <link rel="import" href="polymer-file.html">
<polymer-file readas="dataurl"></polymer-file>
var pFile = document.querySelector('polymer-file'); pFile.addEventListener('polymer-result', function(e) { console.log(this.result); }); pFile.blob = new Blob(['abc'], {type: 'text/plain'}); // Set the file to read pFile.read();
Everything is an element
flexbox...using DOM
<script src="polymer.min.js"></script> <link rel="import" href="polymer-flex-layout.html">
<polymer-flex-layout vertical iscontainer> <div>Header</div> <div flex>Body</div> <div>Footer</div> </polymer-flex-layout>
Polymer elements
non-visual utility elements
Layout
<polymer-layout>
<polymer-flex-layout>
<polymer-grid-layout>
View
<polymer-media-query>
<polymer-page>
Services / libs
<polymer-shared-lib>
<polymer-google-jsapi>
Data
<polymer-localstorage>
<polymer-xhr>
<polymer-jsonp>
<polymer-file>
<polymer-meta>
Behavior / interaction
<polymer-signals>
<polymer-selector>
Polymer UI elements
visual elements




<polymer-ui-accordion>
<polymer-ui-animated-pages>
<polymer-ui-overlay>
<polymer-ui-card>
demo
<polymer-ui-sidebar-menu>
demo
<polymer-ui-tabs>
demo
<polymer-ui-toggle-button>
demo
<polymer-ui-theme-aware>
...
Everything is an element.
Polymer
polymer-project.org/polymer.html
Eliminate boilerplate.
Polymer features
declarative web components
- Declarative element registration:
<polymer-element>
- Declarative inheritance:
<polymer-element extends="...">
- Declarative two-way data-binding:
<input id="input" value="{{foo}}">
- Declarative event handlers:
<button on-click="{{handleClick}}">
- Published properties:
xFoo.bar = 5 <-> <x-foo bar="5">
- Property change watchers:
barChanged: function() {...}
- Automatic node finding:
this.$.input.value = 5
- PointerEvents / PointerGestures by default
Custom elements without Polymer :(
<template id="template">
<style>input { color: orange; }</style>
<input type="text">
</template>
<script>
var proto = Object.create(HTMLElement.prototype, {
createdCallback: {
value: function() {
var t = document.querySelector('#template');
this.createShadowRoot().appendChild(document.importNode(t.content, true));
}
}
});
var MyInput = document.register('my-input', {prototype: proto});
</script>
Custom elements with Polymer :)
declarative custom elements
<script src="polymer.min.js"></script>
-
Create an element definition
<polymer-element name="my-input" constructor="MyInput" noscript> <!-- Note: Polymer creates Shadow DOM from the first <template>. --> <template> <style>input { color: orange; }</style> <input type="text"> </template> </polymer-element>
-
Instantiate - declare it, create DOM, or use
new
in JS<my-input></my-input> // var myInput = document.createElement('my-input'); // var myInput = new MyInput();
Default attributes
User-defined attributes are included on each instance of the element:
<polymer-element name="my-input" customattr class="active"> <template>...</template> </polymer-element> <my-input></my-input>
Instances include your attributes:
<my-input customattr class="active"></my-input>
Define an API
complex elements require more juice...
- Properties/methods are added to
prototype
this
refers to the element itself (e.g.this.localName == "my-input"
)- Can reference external scripts/stylesheets (e.g. CSP friendly)
Publishing properties & data-binding
- Inside the element → use data-binding
- Outside the element → users configure us using attributes
Expressions
Expressions can go anywhere {{}}
live:
<div>Jill has {{ daughter.children.length + son.children.length }} grandchildren</div>
Conditional attributes:
<input type="checkbox" checked?="{{activate}}">
Dynamic classes:
<div class="{{ {active: user.selected, big: user.type == 'super'} | tokenList }}">
<!-- <div class="active big"> -->
Dynamic markup
additional magic for HTML <template>
Conditionals:
<template if="{{ isActive }}">
<!-- shown if isActive property is true -->
</template>
<template if="{{ showDefault || users.length < 10 }}">
...
</template>
Iteration:
<template repeat="{{ user in users }}">
<template repeat="{{ file in user.files }}">
{{ user.name }} owners {{ file.name }}
</template>
</template>
Features in action
data-binding / published properties
<script src="polymer.min.js"></script> <link rel="import" href="polymer-ajax.html">
<polymer-element name="youtube-videos" attributes="query"> <template> <polymer-ajax url="http://gdata.youtube.com/feeds/api/videos/" params="{{params}}" handleAs="json" response="{{response}}" auto></polymer-ajax> <ul> <template repeat="{{entry in response.feed.entry}}"> <li>{{entry.title.$t}}</li> </template> </ul> </template> <script> Polymer('youtube-videos', { ready: function() { this.params = {alt: 'json', q: this.query}; } }); </script> </polymer-element>
<youtube-videos query="cats"></youtube-videos>
Features in action
responsive design...using DOM
<script src="polymer.min.js"></script> <link rel="import" href="polymer-media-query.html">
<polymer-element name="responsive-layout" attributes="responsive"> <template> <polymer-media-query query="max-width:640px" queryMatches="{{isPhone}}"></... <template if="{{isPhone && responsive}}"> <!-- Phone markup --> <content></content> </template> <template if="{{!responsive}}"> <!-- Non-responsive case --> ... </template> </template> <script>Polymer('responsive-layout', {responsive: false});</script> </polymer-element>
<responsive-layout responsive> <div>...</div> </responsive-layout>
Features in action
$ referencing / changed watchers / declarative events
<script src="polymer.min.js"></script> <link rel="import" href="polymer-file.html">
<polymer-element name="read-me" on-click="{{onClick}}"> <template> <polymer-file id="file" readas="arraybuffer" result="{{result}}"></polymer-file> </template> <script> Polymer('read-me', { resultChanged: function() { console.log(this.result); }, onClick: function(e, detail, sender) { this.$.file.read(); } }); </script> </polymer-element>
var el = document.createElement('read-me'); el.blob = new Blob(['abc'], {type: 'text/plain'});
FOUC prevention
Initially hide elements using polymer-veiled
class or manage a list in JS:
-
Add
polymer-veiled
class:<x-foo class="polymer-veiled">If you see me, elements are upgraded!</x-foo> <div class="polymer-veiled"></div>
-
Polymer.veiledElements = ['x-foo', 'div'];
polymer-unveiled
swapped in atWebComponentsReady
event → elements fade-in.- Note:
polymer-veiled
is added to<body>
by default.
Polymer is many things!
Why you should be excited
- Developer productivity
- It's DOM. It's JS. It's CSS → no new APIs to learn!
- say what you mean → readability
- Re-usability at last
- don't reinvent the wheel
- easy interop with other frameworks
- Foster good software engineering paradigms on web (OOP)
A Polymer is a large molecule composed of many repeated subunits, known as monomers.
A Polymer is a large molecule composed of many repeated subunits, known as monomers.
A web app is a large collection of web components composed of many subelements, known as custom elements.
-me