about:me
Addy Osmani
Senior Developer Relations Engineer,
"Learning JavaScript Design Patterns"
"Developing Backbone.js Applications"
Today's agenda
What is Polymer?
Working with Polymer
Example time
Let's go back in time...







Get A T-Shirt!
Elements are the building blocks of the web
Elements are encapsulated
<select> <option>Small</option> <option>Medium</option> <option>Large</option> </select>
Elements are configurable
<select id="schwag"> ... <option disabled>Medium</option> <option disabled>Large</option> <option selected>XX-large</option> </select>
<select size="4" multiple> <option>Do</option> <option>Re</option> <option>Mi</option> ... </select>
<select> <option>Small</option><li>Medium</li><option>Large</option> </select>
Elements are composable
<select> <optgroup label="German Cars"> <option>Mercedes</option> <option>Audi</option> </optgroup> ... </select>
<form> <select name="size"> <option value="s">Small</option> <option value="m">Medium</option> <option value="l">Large</option> </select> </form>
Elements are programmable
var foo = mySelect.selectedIndex;
Good design doesn't date.
So what happened?
Tabs: a common component on the web
Building a tab component today





Pile on the JavaScript
Our markup is terrible
Seriously?
Design isn't just how it looks. It's how it works.
<x-tabs> <x-tab>Tab 1</x-tab> <x-tab>Tab 2</x-tab> <x-tab>Tab 3</x-tab> </x-tabs>
Markup can be meaningful again
<x-tabs> <x-tab selected>...</x-tab> <x-tab>...</x-tab> <x-tab>...</x-tab> </x-tabs>
var tabs = document.createElement('x-tabs'); var tab1 = document.createElement('x-tab'); var tab2 = document.createElement('x-tab'); var tab3 = document.createElement('x-tab'); tabs.appendChild(tab1); tabs.appendChild(tab2); tabs.appendChild(tab3); tab1.setAttribute('selected', true);
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>
Web Components are a set of emerging standards that allow developers to extend HTML.
Templates





Custom Elements





Shadow DOM





HTML Imports





Examples
Native Web Components
What we're used to using
<link rel="stylesheet" type="text/css" href="my-widget.css" /> <script src="my-widget.js"></script>
<div data-my-widget />
$(function() { $('[data-my-widget]').myWidget(); });
div.innerHTML = '<div data-my-widget />'
$(div).find('[data-my-widget]').myWidget();
Using a Custom Element
<link rel="import" href="my-widget.html" /> <my-widget></my-widget>
Reminder: DOM Elements
Elements can be instantiated with markup
<input type="text" />
Elements can be instantiated with JS
var input = document.createElement('input'); el.innerHTML = '<input type="text" />';
Elements can respond to attribute changes
input.setAttribute('value', 'Foobar') input.value; // "Foobar"
DOM Elements
Elements can have hidden internal DOM structures
input.bullet(type="date") <input type="date" /> dateInput.children.length; // 0
Elements can have their own private styles
input.bullet(type="date")
Elements can provide style hooks to their internals
dialog::backdrop { background: black; }
Creating a Custom Element
// JS var MyElement = document.registerElement('my-element'); // or document.createElement(..) // HTML <my-element></my-element>
Extending a Custom Element
// JS var MegaButton = document.registerElement('mega-button', { prototype: Object.create(HTMLButtonElement.prototype) }); // HTML <button is="mega-button">
Callbacks for Custom Elements
document.registerElement('my-element', { prototype: Object.create(HTMLElement.prototype, { // createdCallback, attachedCallback, detachedCallback attributeChangedCallback: { value: function(attr, oldVal, newVal) { this.innerHTML = 'ATTRIBUTE CHANGED!'; } } }) });
Styling a Custom Element
<style> x-foo { display: block; } x-foo > [is="x-bar"] { opacity: 0; } </style> <x-foo> <div is="x-bar"></div> </x-foo>
<style> x-foo { opacity: 1; transition: opacity 300ms; } x-foo:unresolved { opacity: 0; } </style>
shadow = this.createShadowRoot(); shadow.innerHTML = "<style>span { color: green; }</style>" + "<span>I'm green</span>";
Cross-browser support improving but not there yet
Polymer is a library that uses the latest web technologies to let you create custom HTML elements.
Layers of Polymer
Elements
Reusable custom elements (in progress)
Polymer
An opinionated way to work with Web Components
Platform
Web Components polyfills for all
modern browsers
Native
The current browser landscape
Three ways to work with Polymer
Using elements
Creating elements
Utilizing the modern web platform
Three ways to work with Polymer
Using elements
Creating elements
Utilizing the modern web platform
Using
polymer-project.org/docs/elements/
Everything is an element
Polymer UI elements
visual elements




<polymer-ui-accordion>
demo
<polymer-ui-animated-pages>
<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
Collapsible elements
<script src="platform.js"></script> <link rel="import" href="polymer-ui-collapsible.html">
<polymer-ui-collapsible> <h3 class="polymer-ui-collapsible-header">Click Me!</h3> <div> some content... </div> </polymer-ui-collapsible>
Everything is an element
Toggle Button Element
<script src="platform.js"></script> <link rel="import" href="polymer-ui-toggle-button.html">
<polymer-ui-toggle-button offcaption="Nope"> </polymer-ui-toggle-button>
You don't have to know about their internals
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-xhr>
<polymer-jsonp>
<polymer-file>
<polymer-meta>
Behavior / interaction
<polymer-signals>
<polymer-selector>
Everything is an element
flexbox...using DOM
<script src="platform.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>
Everything is an element
AJAX...using DOM
<script src="platform.js"></script> <link rel="import" href="polymer-ajax.html">
<polymer-ajax url="http://gdata.youtube.com/feeds/api/videos/" params='{"q":"chrome", "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();
Everything is an element
responsive design...using DOM (Bonus)
<script src="platform.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>
They're easy to add to your project
Polymer designer (video)
Salesforce elements (video)
Creating
polymer-project.org/polymer.html
Everything is an element
Declarative element registration
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(t.content.cloneNode(true));
}
}
});
var MyInput = document.registerElement('my-input', {prototype: proto});
</script>
Declarative registration with it
<link rel="import" href="polymer.html">
<polymer-element name="my-element" noscript> <template> <style>h2 { color: orange; }</style> <h2>Hello from my-element!</h2> </template> </polymer-element>
<my-element></my-element>
Declarative registration
<link rel="import" href="polymer.html">
<polymer-element name="hello-element"> <template> <h2>I can say hello</h2> </template> <script> Polymer({ sayHello: function() { alert('Howdy folks!'); } }); </script> </polymer-element>
Binding expressions
Binding Expressions
<polymer-element name="owner-element"> <template> <h2>{{owner}} built me with Polymer</h2> </template> <script> Polymer({ owner: 'Addy' }); </script> </polymer-element>
<owner-element></owner-element>
Published properties
Published properties (related)
<polymer-element name="owner-element" attributes="owner"> <template> <h2>{{owner}} built me with Polymer</h2> </template> <script> Polymer({ owner: 'Addy' }); </script> </polymer-element>
<owner-element owner="Alex"></owner-element>
Declarative event handlers
Declarative Event Handlers
<polymer-element name="click-element"> <template> <button on-click="{{setMessage}}">Click me</button> <span>{{message}}</span> </template> <script> Polymer({ message: 'Waiting to be clicked...' setMessage: function() { this.message = 'I was clicked!' } }); </script> </polymer-element>
Automatic node finding
Automatic Node Finding
<polymer-element name="focus-element"> <template> <button on-click="{{setFocus}}">Set Focus</button> <input id="nameInput" type="text"> </template> <script> Polymer({ setFocus: function() { this.$.nameInput.focus(); } }); </script> </polymer-element>
Accessibility isn't forgotten
Accessibility Checklist
- Do all elements have meaningful text alternatives?
- Can all functions be reached via the keyboard without using a mouse?
- Do you have sensible focus order and focus target for each element?
- Are your custom elements marked up to be accessible?
- Can users understand everything without relying on color?
- Is the moving or flashing content in your elements stoppable and safe?
ARIA roles with Polymer (Demo)
<polymer-element name="polymer-ui-ratings" attributes="count value autofocus"> <template> <span id="container" tabindex="0" on-keydown="{{keydownAction}}" role="slider"> <template repeat="{{star in stars}}"> <span id="star" index="{{star.index}}" class="{{star.starClass}}" on-tap="{{updateValue}}"> </span> </template> </span> </template> <script> .....
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
- Support for Web Animations
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
The
polymer-project.org/docs/start/platform
The platform is a layer of polyfills that adds support for emerging standards, like Web Components, to all modern browsers.
Platform polyfills
supporting new web technologies today
Templates





HTML Imports





Custom Elements





Shadow DOM





Additional features include Mutation Observers, Pointer Events, Web Animations, and much more.
As browsers implement the specifications supported by the platform, the need for this
layer decreases.
...till eventually it's all gone.
Polymer Tooling
Helping you stay more productive
- Boilerplate - structure & docs (video)
- Bower - install & share Polymer elements
- Yeoman - scaffold Polymer apps (example)
- Vuncalize - concatenate Web Components
- CustomElements.io - elements by the community