about:me

Web Components?

<gangnam-style></gangnam-style>

<photo-booth></photo-booth>

<button is="mega-button">Mega button</button>

Building a tab component on the web...

Something feels very wrong here...

Readable?

This is how we build web apps!

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>

Need better tools...

Web Components specs


  • Data-binding - pieces are spec'd (Object.observe(), <template>, Mutation Observers)

A collection of new API primitives in the browser

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.

What is it?

  • New type of library for the evolving web (~48KB)
    • goal: support latest version of modern browsers
  • Set of polyfill libraries for the specs
    • Shadow DOM, Custom Elements, HTML Imports, Pointer Events...
  • Sugaring layer
    • expresses opinionated way to use web component concepts together
  • Comprehensive set of UI Components (in progress)

Philosophy / Goals

Philosophy

  1. Utilize the modern web platform.
  2. Embrace DOM. Everything as an element.
  3. Eliminate boilerplate. Remove tediousness of building web apps.

Goals

  1. Provide opinionated guidance on building web component-based apps.
  2. Salt to taste - entire stack is designed to be a la carte
  3. Evolve with the web
  4. Constant feedback loop to web standards

Polymer

polymer-project.org/docs/elements/

Embrace DOM.
Everything as an element.

Everything is an element

perform 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) {
  var response = JSON.parse(this.response);
  console.log(response.feed.entry);
});
...
ajax.go();
Hit run...

Real-world examples of polymer-ajax

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();
Hit run...

Everything is an element

flexbox layout...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>
Header
Body
Footer

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>

...

Reusablilty...the non-visual polymer-elements are used to implement these!

Polymer

polymer-project.org/polymer.html

Eliminate boilerplate.

Polymer's core sugaring features

declarative web components in seconds

  • 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="{{handClick}}">
  • Published properties: xFoo.bar = 5 <-> <x-foo bar="5">
  • Property change watchers: barChanged: function() {...}
  • Automatic node finding: this.$.input.value = 5
Be declarative. Write less code.

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.register('my-input', {prototype: proto});
</script>

Custom elements with Polymer :)

declarative custom elements

<script src="polymer.min.js"></script>
  1. 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>
    

  2. 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>

Complex elements require more juice...

define an API



  • 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

  1. Inside the element → data-binding via the attribute
  2. From outside world → users can initialization the property via its attribute


  • User overrides color but type remains its default ("text")
  • Since val isn't published, can't use it as a bindable attribute.

Features in action

data-binding / published properties

Using <polymer-ajax> in another element:

<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

$ node finding / changed watchers / declarative event handlers

Using <polymer-file> in another element:

<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'});

Expressions

Expressions can go anywhere {{}} live:

<div>Jill has {{ daughter.children.length + son.children.length }} grandchildren</div>

Dynamic classes:

<div class="{{ {active: user.selected, big: user.type == 'super'} | tokenList }}"> 
<!-- <div class="active big"> -->

Conditional attributes:

<input type="checkbox" checked?="{{activate}}">

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

responsive design...using DOM

<script src="polymer.min.js"></script>
<link rel="import" href="polymer-media-query.html">
<polymer-element name="responsive-element" attributes="responsive">
  <template>
    <polymer-media-query query="max-width:640px"
          queryMatches="{{isPhone}}"></polymer-media-query>
    <polymer-media-query query="max-width:1024px"
          queryMatches="{{isTablet}}"></polymer-media-query>

    <template if="{{isPhone && responsive}}">
     <!-- Phone markup. -->
    </template>
    <template if="{{isTablet && responsive}}">
     <!-- Tablet markup. -->
    </template>
    <template if="{{!responsive}}">
     <!-- Default markup for non-responsive case. -->
    </template>

  </template>
  <script>Polymer('responsive-element', {responsive: false});</script>
</polymer-element>

<responsive-element responsive></<responsive-element>

FOUC prevention

Initially hide elements using polymer-veiled class or manage a list in JS:

  1. Add polymer-veiled class:

    <x-foo class="polymer-veiled">If you see me, elements are upgraded!</x-foo>
    <div class="polymer-veiled"></div>
    
  2. Polymer.veiledElements = ['x-foo', 'div'];


  • polymer-unveiled swapped in at WebComponentsReady event → elements fade-in.
  • Note: polymer-veiled is added to <body> by default.

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 is many things!

polymer-project.org

Learn more about the primitives

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)

Thank You!