Hello Lisbon!
Addy Osmani
Senior Developer Relations Engineer,
At the start of the web...
Things were simpler.
Our pages were simpler too.
Web - you've put on some weight.
JavaScript plugins
CSS libraries
float: none;
We can do better.
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 HTML is terrible
Can we do better?
<x-tabs> <x-tab>Tab 1</x-tab> <x-tab>Tab 2</x-tab> <x-tab>Tab 3</x-tab> </x-tabs>
It's easy to write code a browser understands. Good developers write code people can understand.
Design isn't just how it looks. It's how it works.
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
Web Components are an encapsulation mechanism, not a panacea.
Examples
Google Web Components
250+ APIS
Google APIs Explorer
developers.google.com/apis-explorer
Maps API 101
<style> #map { height: 300px; } </style> <div id="map"></div> <script src="http://maps.googleapis.com/maps/api/js"> </script> <script> document.addEventListener('load', function(){ var container = document.querySelector('#map'); var map = new google.maps.Map(container, { zoom: 14 }); }); </script>
Blink-In-JS
Demo<google-signin>
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
HTML Elements
visual elements
non-visual elements
<script>
<title>
<link>
<style>
<template>
<datalist>
<source>
...
...
Core elements
visual elements
<core-menu>
Demo
<core-toolbar>
Demo
<core-pages>
Demo
<core-list>
Demo
<core-collapse>
Demo
<core-overlay>
Demo
<core-scaffold>
Demo
<core-icons>
Demo
...
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
Core elements
non-visual utility elements
Layout
layout.html
<core-layout-grid>
View
<core-media-query>
<core-pages>
Services / libs
<core-shared-lib>
<polymer-google-jsapi>
Data
<core-xhr>
<core-meta>
<polymer-jsonp>
<polymer-file>
Behavior / interaction
<core-selector>
<polymer-signals>
Composability
Good engineering is making a design work with as few new pieces as possible.
<core-selector>
is a building block for..
<my-tabs>
<core-pages>
<core-menu>
- Focused
- Independant
- Reusable
- Small
- Testable
Layout like a boss
Declarative layout system
flexbox...using attributes
<script src="platform.js"></script> <link rel="import" href="layout.html">
<div layout horizontal> <div>Header</div> <div flex>Body</div> <div>Footer</div> </div>
Vertically aligning anything in CSS.
Axis centering
Vertical centering
<div layout horizontal center> <div>Header</div> <div>Body</div> <div>Footer</div> </div>
The Holy Grail
Centered Vertical alignment!!!
<div layout horizontal center center-justified> <div>Header</div> <div>Body</div> <div>Footer</div> </div>
Responsive design
Everything is an element
responsive design...using DOM (Bonus)
<script src="platform.js"></script> <link rel="import" href="core-media-query.html">
<!--Phone--> <core-media-query query="max-width: 40em" queryMatches="{{phone}}"> </core-media-query> <!--Tablet--> <core-media-query query="(min-width: 40.063em) and (max-width: 64em)" queryMatches="{{tablet}}"></core-media-query> <template if="{{phone}}"> .. </template> <template if="{{tablet}}"> .. </template>
core-drawer-panel
A responsive container that combines a left- or right-side drawer panel and a main content area.
<core-drawer-panel> <div drawer> Drawer panel... </div> <div main> Main panel... </div> </core-drawer-panel>
They're easy to add to your project
Designer (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
<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 extension
Declarative extension
<link rel="import" href="polymer.html">
<polymer-element extends="core-selector" name="my-tabs" noscript> <template> <shadow><shadow> </template> </polymer-element>
<my-tabs></my-tabs>
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>
Custom Filters
<polymer-element name="test-element"> <template> {{'Hello World' | uppercase}} {{'Hello World' | lowercase}} {{ colorsArray | last }} {{'Hello World' | reverse}} {{'Hello World' | replace('World','Peeps')}} {{'Lorem Catsum Itsum' | truncate(8) }} {{'Hello World' | wordcount}} </template> <script> ... </polymer-element>
Published properties
Published properties
<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>
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