rootpd@localhost:~$ whoami

Peťo Dulačka

  • Backend dev
    • PHP, Ruby
    • PostgreSQL, MongoDB
    • bit of Cassandra, bit of Android...
  • Not really a frontend guy..
    • Yet I hold a presentation about Web Components.

But first ... YEOMAN!


  • "The Web's scaffolding tool for modern webapps"
  • Generators. Loads of generators.
  • Kick off for any webapp.
  • Supporting Grunt, Gulp, Bower and NPM.
  • YO
#install yeoman
npm install -g yo

#install generators
npm install -g generator-polymer

yo polymer


? Would you like to include core-elements? Yes
? Would you like to include paper-elements? Yes
? Would you like to use SASS/SCSS for element styles? Yes
? Would you like to use libsass? No
   create .gitignore
   create .gitattributes
   create .bowerrc
   create bower.json
   create .jshintrc
   create Gruntfile.js # with already predefined tasks!
   create package.json
   create app\styles\main.scss
   create app\scripts\app.js
   create app\elements\elements.html
   create app\index.html

#bower dependencies output
#npm dependencies output

Web Components


  • HTML5 standard + working drafts (Shadow DOM)
  • HTML is declarative. Be declarative!
  • Sandbox for your custom elements supported by browser
  • Early support, still prefixed.
    (templates, HTML imports, custom elements, Shadow DOM)
  • But hey, we have polyfills!

Browser support

Custom elements

  • Register own HTML elements
  • Set public attributes, behaviour and styles

Browser support


Behavioural elements

  • Elements don't have to be always visible.
  • They can add only behaviour and be reused in other elements.
  • Reusability by proper design. (core-elements vs. paper-elements)
<link rel="import" href="/bower_components/app-router/app-router.html">

  <!-- matches using a wildcard -->
  <app-route path="/customer/*" import="/pages/customer-page.html"></app-route>
  <!-- matches using a path variable -->
  <app-route path="/order/:id" import="/pages/order-page.html"></app-route>
  <!-- matches a pattern like '/word/number' -->
  <app-route path="/^\/\w+\/\d+$/i" regex import="/pages/regex-page.html"></app-route>
  <!-- matches everything else -->
  <app-route path="*" import="/pages/not-found-page.html"></app-route>

Router example usage

  • Multiple routing options
  • Data bindings
<!-- hashchange -->
<a href="#/home">Home</a>
<!-- pushState() -->
<a is="pushstate-anchor" href="/home">Home</a>
<!-- router.go(path, options) -->

<app-route path="/example">
    <p>Inline template FTW!</p>

Styling elements

  • All the styles are sandboxed too (no more prefixing!)
  • But you might want to alter someone else's element


core-scroll-header-panel::shadow .error { /* */ }
core-scroll-header-panel /deep/ .error { /* */ }

/* Polymer only */
<link rel="stylesheet"  href="main.css" shim-shadowdom>


  • Polymer by Google
  • XTag by Mozilla
  • Bosonic
  • Vanilla JavaScript (extending HTMLElement.prototype)


  • Lots of stuff on github
  • CustomElements.IO
  • Component.Kitchen


Polymer? Web Components? What else?

  • "Polymer is a library of polyfills and sugar which enables the use of Web Components in modern browsers."
  • Polymer is just Web Components on the steroids, really.
  • Set of custom elements made by Google - Core elements (mostly) for behaviour and Paper elements for material design.
  • Yeoman supported.
<!-- Polyfill Web Components support for older browsers -->
<script src="components/webcomponentsjs/webcomponents.min.js"></script>

<!-- Import element -->
<link rel="import" href="google-map.html">

<!-- Use element -->
<google-map lat="37.790" long="-122.390"></google-map>

Custom element in Polymer

<!-- elements/custom-element/custom-element.html -->

<!-- Define element -->
<polymer-element name="my-counter" attributes="counter">
    <style> /*...*/ </style>
    <div id="label"><content></content></div>
    Value: <span id="counterVal">{{counter}}</span><br>
    <button on-tap="{{increment}}">Increment</button>
      counter: 0, // Default value
      counterChanged: function() {
      increment: function() {

<!-- Use element -->
<my-counter counter="10">Points</my-counter>

Element life cycle

  • Callbacks available for DOM manipulation.
  • Global "unresolved" keyword to hold the display until all covered elements are ready.


Polymer('tag-name', {
  created: function() { ... },
  ready: function() { ... },
  attached: function () { ... },
  domReady: function() { ... },
  detached: function() { ... },
  attributeChanged: function(attrName, oldVal, newVal) {
    //var newVal = this.getAttribute(attrName);
    console.log(attrName, 'old: ' + oldVal, 'new:', newVal);

Published properties

  • Two-way data bindings
  • Observers + custom events
  • Reflections
<polymer-element name="x-foo" attributes="foo bar baz">
<polymer-element name="x-foo">
      publish: {
        foo: 'I am foo!',
        baz: {
          value: false,
          reflect: true

Killer examples

Google maps

<google-map latitude="37.77493" longitude="-122.41942" fitToMarkers>
  <google-map-marker latitude="37.779" longitude="-122.3892"
      draggable="true" title="Go Giants!"></google-map-marker>
  <google-map-marker latitude="37.777" longitude="-122.38911"></google-map-marker>




 <re-captcha theme="dark" sitekey="yoursitekey"></re-captcha>

Prism.JS syntax highlighting

<prism-js language="markup" escape="true">
  <p data-foo="bar"></p>
    p { color: red; }

Voice elements

<voice-player autoplay text="Welcome to the jungle! hahaha just kidding!"></voice-player>
<voice-player id="mi-elemento" accent="es-ES" text="Me gusta la gasolina"></voice-player>


<!-- 1 Apr 2014 14:30 -->
<time is="local-time" datetime="2014-04-01T16:30:00-08:00"></time>

<!-- (30 minutes ago, an hour ago, 20 hours ago, a day ago...) -->
<time is="relative-time" datetime="2014-04-01T16:30:00-08:00"></time>