Building Your Own Web Components (Tags / Elements)

Agenda

<beer-of-the-day> - Use or Build Your Own Web Component (Tag / Element)

Web Component == Tag == Element e.g. => <beer-of-the-day>, <football-matchday>, <super-button>

Web components machinery lets you build your own HTML tags that you can use as easily as plain old <div> or <span> tags.

<football-matchday> - Use or Build Your Own Web Component (Tag / Element) - Example

Step 1: Import element definition into your page using an HTML import (<link rel='import'>)

<link rel='import' href='football-matchday.html'>

Step 2: Use the new element; once imported the new <football-matchday> element is a first-class HTML element; use like any other

<football-matchday event='at.2014/15'></football-matchday>

Trivia Quiz - How many builtin standard elements (tags) has HTML 4.1? HTML 5?

A) – 50+ ?

B) – 100+ ?

C) – 200+ ?

D) – 500+ ?

E) – 1,000+ ?

F) – 10,000+ ?

All HTML 5 Elements (A-Z)

A <a> <abbr> (x)<acronym> <address> (x)<applet> <area> (5)<article> (5)<aside> (5)<audio> B <b> <base> (x)<basefont> (5)<bdi> <bdo> (x)<bgsound> (x)<big> (x)<blink> <blockquote> <body> <br> <button> C (5)<canvas> <caption> (x)<center> <cite> <code> <col> <colgroup> D (5)<data> (5)<datalist> <dd> <del> (5)<details> <dfn> <dialog> (x)<dir> <div> <dl> <dt> E <em> (5)<embed> F <fieldset> (5)<figcaption> (5)<figure> (x)<font> (5)<footer> <form> (x)<frame> (x)<frameset> G H <h1> <h2> <h3> <h4> <h5> <h6> <head> (5)<header> (x,5)<hgroup> <hr> <html> I <i> <iframe> <img> <input> <ins> (x)<isindex> J K <kbd> (5)<keygen> L <label> <legend> <li> <link> (x)<listing> M (5)<main> <map> (5)<mark> (x)<marquee> (5)<menu> (5)<menuitem> <meta> (5)<meter> N (5)<nav> (x)<nobr> (x)<noframes> <noscript> O <object> <ol> <optgroup> <option> (5)<output> P <p> <param> (5)<picture> (x)<plaintext> <pre> (5)<progress> Q <q> R (5)<rp> (5)<rt> (5)<ruby> S <s> <samp> <script> (5)<section> <select> <small> (5)<source> (x)<spacer> <span> (x)<strike> <strong> <style> <sub> (5)<summary> <sup> T <table> <tbody> <td> <textarea> <tfoot> <th> <thead> (5)<time> <title> <tr> (5)<track> (x)<tt> U <u> <ul> V <var> (5)<video> W (5)<wbr> X Y Z (x)<xmp>

(x) => do NOT use; non-standard, obsolete, or deprecated HTML elements
(5) => new in HTML 5

Welcome to the Web Components Revolution!

Now imagine a world with

100,000+ HTML elements (tags)

or with

1,000,000+ HTML elements (tags)

<super-button> - Use or Build Your Own Web Component (Tag / Element) - More Examples

<super-button></super-button>

<google-map lat='37.79' long='-122.390'></google-map>

<you-tube-video imfeelinglucky='rock me amadeus'></yout-tube-video>

<pdf-js src='wien.pdf'></pdf-js>

<marked-js>
## Markdown Renderer

* code in `JavaScript`
* realtime formatting

_many_ more goodies.
</marked-js>

Q: What about namespaces? How’s a custom element different from a built-in standard element e.g. <div>, <span>?

A: Custom elements MUST use a dash (-) e.g. <beer-of-the-day>, <football-matchday>, <super-button>.

Paper Elements (Material Design) - “Real World” Web Components

Introduced to the World at the Google I/O 2014 Conference

<paper-button> <paper-checkbox> <paper-dialog-transition> <paper-dialog> <paper-fab> <paper-focusable> <paper-icon-button> <paper-input> <paper-item> <paper-menu-button-overlay> <paper-menu-button> <paper-progress> <paper-radio-button> <paper-radio-group> <paper-ripple> <paper-shadow> <paper-slider> <paper-tab> <paper-tabs> <paper-toast> <paper-toggle-button>

Usage:

<paper-dialog heading='Hello Vienna.js'>
  <p>Lorem ipsum ....</p>
  <paper-button label='More Info...' dismissive></paper-button>
  <paper-button label='Decline' affirmative></paper-button>
  <paper-button label='Accept' affirmative autofocus></paper-button>
</paper-dialog>

Google Web Components - “Real World” Web Components (Cont.)

More info @ github.com/GoogleWebComponents

Web Components Machinery - New Web Standard Building Blocks

New (Built-in) Browser Machinery

HTML Templates

(<template>) - W3C Spec

Custom Elements

(<element>) - W3C Spec

HTML Imports

(<link rel='import'> - include and (re)use HTML documents in other HTML documents) - W3C Spec

Shadow DOM

(createShadowRoot() - DOM trees inside DOM trees; hide DOM trees under shadow roots) - W3C Spec

CSS Scoping Module Level 1

W3C Spec

Higher-Level Machinery (w/ JavaScript Libraries)

MDV (Model Driven Views)

(repeat='{{ greetings }}') - JavaScript Library for two-way databinding (incl. auto-updates w/ change observers ‘n’ more)

Web Components Machinery - New Web Standard Building Blocks - Can I Use?

Tl;dr:

Chrome 36+ ships all the web components machinery (built into the browser and turned on by default)

Firefox ships “lite” web components machinery (shipping HTML Templates and Custom Elements; NOT shipping (in development) Shadow DOM and HTML Imports)

(Source: Polymer Browser Compatibility)

Web Components Machinery - New Web Standard Building Blocks - Can I Use?

HTML Templates (<template>) - Standard

Custom Elements (<element>) - Work-In-Progress

Shadow DOM (createShadowRoot(), Scoped CSS) - Work-In-Progress

Web Compontens Machinery - Industry (Browser) News / Support

The Good - Google, Mozilla

Google I/O 2014 - Paper Elements ‘n’ Material Design => Google wants you to build web apps (running anywhere e.g. desktop, tablet, phone) - everything in HTML/CSS/JS.

Firefox OS => Mozilla wants you to build mobile web apps for Firefox OS - everything in HTML/CSS/JS.

The Bad ‘n’ Ugly - Apple, Microsoft

No news. No suprise. Apple wants you to build iOS apps (Cocoa/ObjectiveC) and Microsoft wants you to build - suprise, suprise - Windows apps (Win32/.NET/WinRT/C#) first.

What’s X-Tag? What’s Polymer?

X-Tag

Small JavaScript library by Mozilla - lets you use and build custom tags for all modern browsers (in theory; in practice looks like an orphan - last news update (blog post) dated June 15th, 2013, that is, more than a year ago; github repo about two commits per month (!))

More info @ x-tags.org ‘n’ github.com/x-tag

Polymer

Library by Google - lets you use and build custom tags; uses web components machinery built into modern browsers; (ugly) pollyfills for older browsers.

More info @ www.polymer-project.org ‘n’ github.com/polymer

Example 1 - <beer-of-the-day> Tag Definition

beer-of-the-day.html

<polymer-element name='beer-of-the-day'>

  <style>
    p { background-color: yellow; }
  </style>

  <template>
    <p>I'm a fan of <b>Ottakringer Wiener Original</b>
        and this is my Shadow DOM.
    </p>
  </template>

  <script>
    <!-- no JavaScript needed for now;
          sorry ;-)
      -->
  </script>

</polymer-element>

Example 1 - <beer-of-the-day> Tag Usage

<html>
  <head>

    <!-- 1. Shim/polyfill missing web components machinery -->
    <script src='js/libs/polymer-min.js'></script>

    <!-- 2. Load custom tag (e.g HTML Imports in action) -->
    <link rel='import' href='beer-of-the-day.html'>

  </head>
  <body>

    <!-- 3. Use custom tag -->
    <beer-of-the-day></beer-of-the-day>

  </body>
</html>

Example 2 - <football-matchday> Österr. Bundesliga Matchday Widget

What’s football.js?

Football widgets in JavaScript using the football.db HTTP JSON(P) API

The old way in JavaScript. Usage Example:

<script src='js/football.js'></script>

<div id='bl'></div>

<script>
  MatchdayWidget.create( '#bl', { event: 'at.2014/15' } );
</script>

The new way:

<!-- step 1: HTML Imports -->
<link rel='import' href='football-matchday.html'>

<!-- step 2: use custom tag -->
<football-matchday event='at.2014/15'></football-matchday>

Example 2 - <football-matchday> - MDV (Model Driven Views)

Matchday Data as JavaScript Objects

{
  "event":{"key":"at.2014/15","title":"Österr. Bundesliga 2014/15"},
  "round":{"pos":6,"title":"6. Runde","start_at":"2014/08/23","end_at":"2014/08/24"},
  "games":[{"team1_title":"Sturm Graz","team1_code":"STU","team2_title":"Wolfsberger AC","team2_code":"WAC","play_at":"2014/08/23","score1":1,"score2":2},
           {"team1_title":"RB Salzbrug","team1_code":"RBS","team2_title":"SCR Altach","team2_code":"ALT","play_at":"2014/08/23","score1":5,"score2":0},
           {"team1_title":"SV Ried","team1_code":"RIE","team2_title":"SV Grödig","team2_code":"SVG","play_at":"2014/08/23","score1":2,"score2":2},
           {"team1_title":"Wr. Neustadt","team1_code":"WRN","team2_title":"Admira Wacker","team2_code":"ADM","play_at":"2014/08/23","score1":5,"score2":4},
           {"team1_title":"Austria Wien","team1_code":"AUS","team2_title":"Rapid Wien","team2_code":"RAP","play_at":"2014/08/24","score1":2,"score2":2}]
}
<template>
  <div class='football-widget'>
    <h3>
      {{ data.event.title }}  -  {{ data.round.title }}
    </h3>
  </div>
</template>

Example 2 - <football-matchday> Widget - Nested Templates

<template>
  <div class='football-widget'>
    <h3>
      {{ data.event.title }}  -  {{ data.round.title }}
    </h3>

   <table>
   <template repeat='{{data.games}}'>
   <tr>
    <td>
      {{ play_at }}
     </td>
     <td style='text-align: right;'>
       {{ team1_title }} ({{ team1_code }})
     </td>

     <td>
       {{ score1 }} - {{ score2 }}
     </td>
     <td>
      {{ team2_title }} ({{ team2_code }})
     </td>
   </tr>
   </template>
   </table>  
</template>

Example 2 - <football-matchday> - All Together Now

<polymer-element name='football-matchday' attributes='event'>
 
  <template>
   <style>
     .football-widget {
        border: 1px solid green;
        padding: 4px;
        margin: 10px;
     }
    </style>

   <div class='football-widget'>
    <h3>
      {{ data.event.title }}  -  {{ data.round.title }}
    </h3>

    <table>
   <template repeat='{{data.games}}'>
   <tr>
    <td>
      {{ play_at }}
     </td>
     <td style='text-align: right;'>
       {{ team1_title }} ({{ team1_code }})
     </td>

     <td>
       {{ score1 }} - {{ score2 }}
     </td>
     <td>
      {{ team2_title }} ({{ team2_code }})
     </td>
   </tr>
   </template>
    </table>

 </div>
 </template>
  
  <script>
    Polymer('football-matchday', {
      // event: 'at.2014/15',
      data: {
       "event":{"key":"at.2014/15","title":"Österr. Bundesliga 2014/15"},
       "round":{"pos":6,"title":"6. Runde","start_at":"2014/08/23","end_at":"2014/08/24"},
       "games":[{"team1_title":"Sturm Graz","team1_code":"STU","team2_title":"Wolfsberger AC","team2_code":"WAC","play_at":"2014/08/23","score1":1,"score2":2},
                {"team1_title":"RB Salzbrug","team1_code":"RBS","team2_title":"SCR Altach","team2_code":"ALT","play_at":"2014/08/23","score1":5,"score2":0},
                {"team1_title":"SV Ried","team1_code":"RIE","team2_title":"SV Grödig","team2_code":"SVG","play_at":"2014/08/23","score1":2,"score2":2},
                {"team1_title":"Wr. Neustadt","team1_code":"WRN","team2_title":"Admira Wacker","team2_code":"ADM","play_at":"2014/08/23","score1":5,"score2":4},
                {"team1_title":"Austria Wien","team1_code":"AUS","team2_title":"Rapid Wien","team2_code":"RAP","play_at":"2014/08/24","score1":2,"score2":2}]
       } 
    });
  </script>
</polymer-element>

Example 2 - <football-matchday> - Usage

<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>
    <title>football.js</title>
    <script src='js/libs/polymer.min.js'></script>
    <link rel='import' href='football-matchday.html'>
  </head>
  <body>
    <football-matchday event='at.2014/15'></football-matchday>
  </body>
</html>

That’s it.

Thanks - Questions? Comments?

Learn More

Appendix: Web Components Machinery - New Web Standard Building Blocks - Sources

Chrome

Firefox

Internet Explorer

Site source on github (creative commons licensed) build w/ Node.js; modern IE ?! - is this possible? - IE and modern?

Apple

Appendix: New Anti-Pattern? Single Web Component App <my-beer-app>

<!DOCTYPE html>
<html>
  <head>
    <title>My Beer App</title>
    <link rel='import' href='my-beer-app.html'>
  </head>
  <body>
    <my-beer-app>
  </body>
</html>

Anti-Pattern? Why? Why Not?

Appendix: Vanilla JS Example - HTML5 Rocks Article Series

HTML5 Rocks Series

Appendix: Vanilla JS Example - Register a Custom Web Element

var proto = Object.create(HTMLElement.prototype);

proto.createdCallback = function() {
  this.textContent = 'I'm an x-foo!';
};

proto.foo = function() {
  console.log('foo() called');
};

var XFoo = document.registerElement('x-foo', {
  prototype: proto
});

Now use like:

var xfoo = new XFoo();   // or
var xfoo = document.createElement('x-foo');

document.body.appendChild( xfoo );

or

<x-foo>   <!-- OMG! It's HTML! -->

Appendix: Vanilla JS Example - Create a Shadow DOM

Appendix: Vanilla JS Example - Stamp-Out a Template