Why You Should be Using Web Components Right Now. And How. ForwardJS July 2015

Preview:

Citation preview

Why you should be using Web Components Now.And How.

PHIL @LEGGETTERHead of Developer Relations

1 / 157

2 / 157

3 / 157

What we'll coverWhat are Web Components?The State of Web ComponentsComponentised Web Apps NowWhy Web Components are the Future!

4 / 157

What are Web Components?5 / 157

What are Web Components?Custom ElementsHTML TemplatesShadow DOMHTML Imports

6 / 157

Custom Elements

7 / 157

Elements - Structure & Meaning<!doctype html><html> <head> <meta charset="utf-8" /> <title>HTML Elements</title> <meta name="description" content="" /> <link rel="stylesheet" href="css/stylez.css" /> </head> <body> <nav> <ul> <li><a href="#">Home</a></li> </ul> </nav> <header> <p>Hello world! This (part of) is HTML5 Boilerplate.</p> </header> <main> <article>Ohhhh. Interesting</article> </main> <footer>&copy; me</footer> <script src="js/script.js"></script> </body></html>

8 / 157

Elements in "apps"

9 / 157

Elements. Arrrgghhh!

10 / 157

<Custom Elements />

11 / 157

<Custom Elements />

Bring semantic markup backMore than just markupIMHO the most important part of Web Components

12 / 157

Custom Elements: A new Gmail<!doctype html><html> <head> <meta charset="utf-8"> <title>A new Gmail?</title> <meta name="description" content=""> </head> <body>

13 / 157

Custom Elements: A new Gmail<!doctype html><html> <head> <meta charset="utf-8"> <title>A new Gmail?</title> <meta name="description" content=""> </head> <body>

<header> <img src="img/logo.png" alt="Google Logo" /> <gmail-search /> <gmail-account-strip /> </header>

14 / 157

Custom Elements: A new Gmail<!doctype html><html> <head> <meta charset="utf-8"> <title>A new Gmail?</title> <meta name="description" content=""> </head> <body>

<header> <img src="img/logo.png" alt="Google Logo" /> <gmail-search /> <gmail-account-strip /> </header>

<gmail-side-bar> <nav is="gmail-labels"></nav> <gmail-contacts /> </gmail-sidebar>

15 / 157

Custom Elements: A new Gmail<!doctype html><html> <head> <meta charset="utf-8"> <title>A new Gmail?</title> <meta name="description" content=""> </head> <body>

<header> <img src="img/logo.png" alt="Google Logo" /> <gmail-search /> <gmail-account-strip /> </header>

<gmail-side-bar> <nav is="gmail-labels"></nav> <gmail-contacts /> </gmail-sidebar>

<main> <nav is="gmail-categories"></nav> <gmail-email-list /> </main>

16 / 157

Custom Elements: A new Gmail<!doctype html><html> <head> <meta charset="utf-8"> <title>A new Gmail?</title> <meta name="description" content=""> </head> <body>

<header> <img src="img/logo.png" alt="Google Logo" /> <gmail-search /> <gmail-account-strip /> </header>

<gmail-side-bar> <nav is="gmail-labels"></nav> <gmail-contacts /> </gmail-sidebar>

<main> <nav is="gmail-categories"></nav> <gmail-email-list /> </main>

<hangouts /> </body></html>

17 / 157

Tools, Tips & Tricks for buildingComponentised Web Apps

18 / 157

<img src="http://avatars.io/twitter/leggetter" />

<img src="http://avatars.io/instagram/leggetter" />

<img src="http://avatars.io/gravatar/phil@pusher.com" />

<img src="http://api.skype.com/users/pleggetter/profile/avatar" />

Start Simple - An Avatar

19 / 157

Custom Elements

<my-avatar service="twitter" username="leggetter" />

20 / 157

Custom Elements

<my-avatar service="twitter" username="leggetter" />

<script>var MyAvatarPrototype = Object.create(HTMLElement.prototype);

21 / 157

Custom Elements

<my-avatar service="twitter" username="leggetter" />

<script>var MyAvatarPrototype = Object.create(HTMLElement.prototype);

MyAvatarPrototype.createdCallback = function() { var username = this.getAttribute('username'); var service = this.getAttribute('service');

22 / 157

Custom Elements

<my-avatar service="twitter" username="leggetter" />

<script>var MyAvatarPrototype = Object.create(HTMLElement.prototype);

MyAvatarPrototype.createdCallback = function() { var username = this.getAttribute('username'); var service = this.getAttribute('service');

var url = 'http://avatars.io/' + service + '/' + username;

23 / 157

Custom Elements

<my-avatar service="twitter" username="leggetter" />

<script>var MyAvatarPrototype = Object.create(HTMLElement.prototype);

MyAvatarPrototype.createdCallback = function() { var username = this.getAttribute('username'); var service = this.getAttribute('service');

var url = 'http://avatars.io/' + service + '/' + username;

var img = document.createElement( 'img' ); img.setAttribute('src', url); this.appendChild(img);};

24 / 157

Custom Elements

<my-avatar service="twitter" username="leggetter" />

<script>var MyAvatarPrototype = Object.create(HTMLElement.prototype);

MyAvatarPrototype.createdCallback = function() { var username = this.getAttribute('username'); var service = this.getAttribute('service');

var url = 'http://avatars.io/' + service + '/' + username;

var img = document.createElement( 'img' ); img.setAttribute('src', url); this.appendChild(img);};

document.registerElement('my-avatar', { prototype: MyAvatarPrototype});</script>

Define your own elements. 25 / 157

<my-avatar service="twitter" username="leggetter" />

<my-avatar service="instagram" username="leggetter" />

<my-avatar service="twitter" username="forwardjs" />

<my-avatar />

26 / 157

Custom Elements - Extending

<img is="my-avatar-ext" service="twitter" username="leggetter" />

27 / 157

Custom Elements - Extending

<img is="my-avatar-ext" service="twitter" username="leggetter" />

<script>var MyAvatarExtPrototype = Object.create(HTMLImageElement.prototype);

28 / 157

Custom Elements - Extending

<img is="my-avatar-ext" service="twitter" username="leggetter" />

<script>var MyAvatarExtPrototype = Object.create(HTMLImageElement.prototype);

MyAvatarExtPrototype.createdCallback = function() { var username = this.getAttribute('username'), service = this.getAttribute('service'), url = 'http://avatars.io/' + service + '/' + username;

this.setAttribute('src', url);};

29 / 157

Custom Elements - Extending

<img is="my-avatar-ext" service="twitter" username="leggetter" />

<script>var MyAvatarExtPrototype = Object.create(HTMLImageElement.prototype);

MyAvatarExtPrototype.createdCallback = function() { var username = this.getAttribute('username'), service = this.getAttribute('service'), url = 'http://avatars.io/' + service + '/' + username;

this.setAttribute('src', url);};

document.registerElement('my-avatar-ext', { prototype: MyAvatarExtPrototype, extends: 'img'});</script>

Extending existing elements30 / 157

Custom Elements - Lifecycle

createdCallbackattachedCallbackdetachedCallbackattributeChangedCallback(attrName, oldVal,newVal)

31 / 157

Create Elements using JavaScript

<script>function createPhils() { var tooManyPhils = 104; var phils = 0; do { var el = document.createElement( 'my-avatar' ); el.setAttribute('service', 'twitter'); el.setAttribute('username', 'leggetter'); document.getElementById( 'phils' ).appendChild( el ); ++phils; } while( phils < tooManyPhils );}</script>

Create Phils

32 / 157

Why Custom Elements?

33 / 157

Templates

Native HTML Templating Support

34 / 157

<script type="text/x-handlebars-template"> <div class="entry"> <h1>{{title}}</h1> <div>{{body}}</div> </div></script>

35 / 157

HTML Templates Create Avatar

<template id="my-avatar-template"> <style> .container { background-color: gold; } <!-- omitted for brevity --> </style> <div class="container"> <img class="avatar" /> <span class="username"></span> <span class="service"></span> </div></template>

36 / 157

HTML Templates Create Avatar

<template id="my-avatar-template"> <style> .container { background-color: gold; } <!-- omitted for brevity --> </style> <div class="container"> <img class="avatar" /> <span class="username"></span> <span class="service"></span> </div></template>

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

MyAvatarTmplPrototype.createdCallback = function() { // get attributes & build url

37 / 157

HTML Templates Create Avatar

<template id="my-avatar-template"> <style> .container { background-color: gold; } <!-- omitted for brevity --> </style> <div class="container"> <img class="avatar" /> <span class="username"></span> <span class="service"></span> </div></template>

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

MyAvatarTmplPrototype.createdCallback = function() { // get attributes & build url

var content = document.querySelector( '#my-avatar-template' ).content; var el = document.importNode( content, true );

38 / 157

HTML Templates Create Avatar

<template id="my-avatar-template"> <style> .container { background-color: gold; } <!-- omitted for brevity --> </style> <div class="container"> <img class="avatar" /> <span class="username"></span> <span class="service"></span> </div></template>

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

MyAvatarTmplPrototype.createdCallback = function() { // get attributes & build url

var content = document.querySelector( '#my-avatar-template' ).content; var el = document.importNode( content, true );

el.querySelector( '.avatar' ).setAttribute( 'src', url ); el.querySelector( '.username' ).textContent = username; el.querySelector( '.service' ).textContent = service; this.appendChild( el );};

39 / 157

HTML Templates Create Avatar

<template id="my-avatar-template"> <style> .container { background-color: gold; } <!-- omitted for brevity --> </style> <div class="container"> <img class="avatar" /> <span class="username"></span> <span class="service"></span> </div></template>

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

MyAvatarTmplPrototype.createdCallback = function() { // get attributes & build url

var content = document.querySelector( '#my-avatar-template' ).content; var el = document.importNode( content, true );

el.querySelector( '.avatar' ).setAttribute( 'src', url ); el.querySelector( '.username' ).textContent = username; el.querySelector( '.service' ).textContent = service; this.appendChild( el );};

document.registerElement('my-avatar-tmpl', { prototype: MyAvatarTmplPrototype

40 / 157

Why native HTML Templates?

Libraries → NativeNative benefitsDocument fragment = lightweightInert until cloned/used

41 / 157

Shadow DOM

DOM/CSS "scoping" / protection

42 / 157

Shadow DOM - Already using it

43 / 157

Shadow DOM - Problems it solves

44 / 157

Styles <span class="container">Bleed!</span>

<template id="my-avatar-tmpl"> <style> .container { background-color: cyan; } ...

<my-avatar-tmpl service="twitter" username="leggetter" />

Styles Bleed! Create

Shadow DOM - Problems it solves

45 / 157

Styles <span class="container">Bleed!</span>

<template id="my-avatar-tmpl"> <style> .container { background-color: cyan; } ...

<my-avatar-tmpl service="twitter" username="leggetter" />

Styles Bleed! Create

<template id="my-avatar-template"> <div class="container"> <img id="avatar" /> ...</template>

Global DOM e.g. id attributes

Shadow DOM - Problems it solves

46 / 157

Shadow DOM - In Action Create ForwardJS

47 / 157

Shadow DOM - In Action Create ForwardJS

<template id="my-avatar-shadow-tmpl"> <style> .container { background-color: red; color: white; } ... </style> <div class="container"> <img id="avatar" /> ... </div></template>

48 / 157

Shadow DOM - In Action Create ForwardJS

<template id="my-avatar-shadow-tmpl"> <style> .container { background-color: red; color: white; } ... </style> <div class="container"> <img id="avatar" /> ... </div></template>

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

MyAvatarShadowPrototype.createdCallback = function() { // get attributes & build url

var content = document.querySelector( '#my-avatar-shadow-tmpl' ).content;

49 / 157

Shadow DOM - In Action Create ForwardJS

<template id="my-avatar-shadow-tmpl"> <style> .container { background-color: red; color: white; } ... </style> <div class="container"> <img id="avatar" /> ... </div></template>

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

MyAvatarShadowPrototype.createdCallback = function() { // get attributes & build url

var content = document.querySelector( '#my-avatar-shadow-tmpl' ).content;

this.shadow = this.createShadowRoot(); this.shadow.appendChild( document.importNode( content, true ) );

50 / 157

Shadow DOM - In Action Create ForwardJS

<template id="my-avatar-shadow-tmpl"> <style> .container { background-color: red; color: white; } ... </style> <div class="container"> <img id="avatar" /> ... </div></template>

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

MyAvatarShadowPrototype.createdCallback = function() { // get attributes & build url

var content = document.querySelector( '#my-avatar-shadow-tmpl' ).content;

this.shadow = this.createShadowRoot(); this.shadow.appendChild( document.importNode( content, true ) );

this.shadow.querySelector( '#avatar' ).setAttribute( 'src', url ); this.shadow.querySelector( '#username' ).textContent = username; this.shadow.querySelector( '#service' ).textContent = service;};

51 / 157

Shadow DOM - In Action Create ForwardJS

<template id="my-avatar-shadow-tmpl"> <style> .container { background-color: red; color: white; } ... </style> <div class="container"> <img id="avatar" /> ... </div></template>

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

MyAvatarShadowPrototype.createdCallback = function() { // get attributes & build url

var content = document.querySelector( '#my-avatar-shadow-tmpl' ).content;

this.shadow = this.createShadowRoot(); this.shadow.appendChild( document.importNode( content, true ) );

this.shadow.querySelector( '#avatar' ).setAttribute( 'src', url ); this.shadow.querySelector( '#username' ).textContent = username; this.shadow.querySelector( '#service' ).textContent = service;};

document.registerElement('my-avatar-shadow', { prototype: MyAvatarShadowPrototype

52 / 157

Why Shadow DOM?

DOM & CSS ScopingProtection for all: Page and ElementEncapsulation

53 / 157

HTML Imports

Loading & Dependency Management

54 / 157

HTML Imports - Example

Before

<link rel="stylesheet" href="bootstrap.css" /><link rel="stylesheet" href="fonts.css" /><script src="jquery.js"></script><script src="bootstrap.js"></script><script src="bootstrap-tooltip.js"></script><script src="bootstrap-dropdown.js"></script>

55 / 157

HTML Imports - Example

Before

<link rel="stylesheet" href="bootstrap.css" /><link rel="stylesheet" href="fonts.css" /><script src="jquery.js"></script><script src="bootstrap.js"></script><script src="bootstrap-tooltip.js"></script><script src="bootstrap-dropdown.js"></script>

After

<link rel="import" href="bootstrap.html" />

56 / 157

HTML Imports - Compositionteam-pusher.html

57 / 157

HTML Imports - Compositionteam-pusher.html

<link rel="import" href="my-avatar-import.html" />

58 / 157

HTML Imports - Compositionteam-pusher.html

<link rel="import" href="my-avatar-import.html" />

<template id="team-pusher-tmpl"> <style> </style>

<my-avatar-import service="twitter" username="maxthelion" /> <my-avatar-import service="twitter" username="copypastaa" /> ... <my-avatar-import service="twitter" username="leggetter" /></template>

...

59 / 157

HTML Imports - Compositionteam-pusher.html

<link rel="import" href="my-avatar-import.html" />

<template id="team-pusher-tmpl"> <style> </style>

<my-avatar-import service="twitter" username="maxthelion" /> <my-avatar-import service="twitter" username="copypastaa" /> ... <my-avatar-import service="twitter" username="leggetter" /></template>

<script> var TeamPusherPrototype = Object.create(HTMLElement.prototype);

TeamPusherPrototype.createdCallback = function() { // Get template, createShadowRoot etc. };

document.registerElement('team-pusher', { prototype: TeamPusherPrototype });</script>

...

60 / 157

HTML Imports - Composition Demo

<link rel="import" href="assets/team-pusher.html" />

<team-pusher></team-pusher>

61 / 157

HTML Imports - Composition Demo

<link rel="import" href="assets/team-pusher.html" />

<team-pusher></team-pusher>

maxtheliontwitter

copypastaatwitter

zimbatmtwitter

loicdumastwitter

mdpyetwitter

olga_dukovatwitter

pawel_ledwontwitter

hamchapmantwitter

LaurieWang_twitter

swstaggtwitter

vivangkumartwitter

willsewell_twitter

davidrbiggstwitter

leggettertwitter

We're Hiring! pusher.com/jobs

62 / 157

Why Use HTML Imports?Bundle JS/HTML/CSS → single URLBasic dependency managementSharing, Reuse, Composition

63 / 157

Gotchas / Patterns!

64 / 157

Get & use document from the currentScript

( function( currentScript ) {

var importDoc = currentScript.ownerDocument;

TeamPusherPrototype.createdCallback = function() { var content = importDoc.querySelector( '#team-pusher-tmpl' ).content; // ... };

} )( document._currentScript || document.currentScript );

65 / 157

importNode and NOT cloneNode for Template

// Note: use ownerDocvar content = ownerDoc.querySelector( '#my-template' );

var clone = ownerDoc.importNode( content, true );

66 / 157

You can't <link> into the Shadow DOM

<template> <link rel="stylesheet" href="path/to/style.css" /></template>

67 / 157

The State of...

68 / 157

The State of Custom Elements

isConcerns around Accessibility

Point of UpgradeWhen HTMLElement is transformed into Custom Element

69 / 157

The State of Templates ✔

70 / 157

The State of Shadow DOM

<content select="tag" />Declarative element content placement

71 / 157

The State of Shadow DOM

<content select="tag" />Declarative element content placement

element.createShadowRoot({ mode:'closed' });

protecting shadowRoot

72 / 157

The State of Shadow DOM

<content select="tag" />Declarative element content placement

element.createShadowRoot({ mode:'closed' });

protecting shadowRoot.foo >>> div { color: red }

Shadow piercing combinators...

73 / 157

The State of HTML Imports

74 / 157

Firefox

https://hacks.mozilla.org/2014/12/mozilla-and-web-components/

“ Mozilla will not ship an implementation ofHTML Imports. We expect that once JavaScriptmodules ... is shipped, the way we look at thisproblem will have changed.

75 / 157

Essential "State of" Reading

Wilson Page - The State of Web ComponentsMicrosoft Edge Team - Bringing componentization to the web: Anoverview of Web Components

76 / 157

The State of Browsers

77 / 157

Microsoft Edge

78 / 157

Apple's updated feedback on Custom Elements and Shadow DOM

From: Maciej Stachowiak <mjs@apple.com> Date: Mon, 20 Jul 2015 18:17:24 -0700Message-id: <E9841AA1-9255-4324-946E-E785B15DAE93@apple.com> To: public-webapps <public-webapps@w3.org>

A while back we sent a consolidated pile of feedback on the Web Components family of specs. In preparation for tomorrow's F2F, here is an update on our positions. We've also changed the bugzilla links to point to relevant github issues instead.

We're only covering Custom Elements (the main expected topic), and also Shadow DOM (in case that gets discussed too).

I. ==== Custom Elements ====

A. ES6 classes / Upgrade / Synchronous Constructors 1. In general, we support the "synchronous constructors" approach to the "prototype swizzling" approach, as the lesser evil. While tricky to implement correctly, it makes a lot more sense and fits more naturally into the language. We are willing to do the work to make it feasible. 2. Custom elements should support initialization using an ES6 class constructo instead of a separate callback. <https://github.com/w3c/webcomponents/issues/139 <https://www.w3.org/Bugs/Public/show_bug.cgi?id=28541>> 3. We don’t think upgrading should be supported. The tradeoffs of different options have been much-discussed. <https://github.com/w3c/webcomponents/issues/134 <https://www.w3.org/Bugs/Public/show_bug.cgi?id=28544>> 4. Specifically, we don't really like the "Optional Upgrades, Optional Constructors" proposal (seems like it's the worst of both worlds in terms of complexity and weirdness) or the "Parser-Created Classes" proposal (not clear how this even solves the problem).

B. Insertion/Removal Callbacks 1. We think the current attached/detached callbacks should be removed. They don’t match core DOM concepts and insert/remove is a more natural bracket. The primitives should be insertedIntoDocument / removedFromDocument and inserted / removed. If you care about whether your document is rendered, look at its defaultView property. <https://github.com/w3c/webcomponents/issues/286> 2. We think inserted/removed callbacks should be added, for alignment with DOM. <https://github.com/w3c/webcomponents/issues/222>

C. Inheritance for Built-ins 1. We think support for inheritance from built-in elements (other than HTMLElement/SVGElement) should be omitted from a cross-browser v1. It raises complex implementation issues. <https://github.com/w3c/webcomponents/issues/133 <https://www.w3.org/Bugs/Public/show_bug.cgi?id=28547>>

D. Syntactic Sugar / Developer Ergonomics 1. We think it would be useful (perhaps post-v1) to make it simpler to create a custom element that is always instantiated with a shadow DOM from a template. Right now, this common use case requires script and a template in separate places, and a few lines of confusing

79 / 157

Safari

Can I use ? Settingsweb components4 results found

# Global 67.55%

U.K. 70.69%

IE / Edge Firefox Chrome Safari Opera iOS Safari * Opera Mini * AndroidBrowser

* Chrome forAndroid

8

9

10

11

Edge

31

38

39

40

41

42

31

36

37

39

40

42

43

44

45

46

47

7

7.1

8

9

30

31

32

7.1

8.4

9

8

4.1

4.3

4.4

4.4.4

40 42

HTML templates - LS

Method of declaring a portion of reusable markup that is parsedbut not rendered until cloned.

Current aligned Usage relative Show all

80 / 157

State of Browser Support

Componentised Web Apps Now -questions?

Should native browser support stop us thinking about building componentised

web apps?

85 / 157

Componentised Web Apps Now -questions?

Should native browser support stop us thinking about building componentised

web apps?

No!

86 / 157

Componentised Web Apps Now -questions?

Should native browser support stop us thinking about building componentised

web apps?

No!

Should we be build componentised web apps anyway?

87 / 157

Componentised Web Apps Now -questions?

Should native browser support stop us thinking about building componentised

web apps?

No!

Should we be build componentised web apps anyway?

We're already building web apps out of components right now!

88 / 157

JavaScript

Libraries & Frameworks

89 / 157

AngularJS

90 / 157

AngularJS<script src="js/angular.min.js"></script>

91 / 157

AngularJS<script src="js/angular.min.js"></script>

<script>angular.module('demo', []) .directive('ngAvatar', function () { return {

92 / 157

AngularJS<script src="js/angular.min.js"></script>

<script>angular.module('demo', []) .directive('ngAvatar', function () { return {

restrict:"AEC",

93 / 157

AngularJS<script src="js/angular.min.js"></script>

<script>angular.module('demo', []) .directive('ngAvatar', function () { return {

restrict:"AEC",

scope: { service: '@', username: '@' },

94 / 157

AngularJS<script src="js/angular.min.js"></script>

<script>angular.module('demo', []) .directive('ngAvatar', function () { return {

restrict:"AEC",

scope: { service: '@', username: '@' },

template: '<img src="http://avatars.io/' + '{{service}}/{{username}}" />' }; });</script>

<body ng-app="demo">

95 / 157

AngularJS<script src="js/angular.min.js"></script>

<script>angular.module('demo', []) .directive('ngAvatar', function () { return {

restrict:"AEC",

scope: { service: '@', username: '@' },

template: '<img src="http://avatars.io/' + '{{service}}/{{username}}" />' }; });</script>

<body ng-app="demo">

<ng-avatar service="twitter" username="leggetter" />

96 / 157

AngularJS<script src="js/angular.min.js"></script>

<script>angular.module('demo', []) .directive('ngAvatar', function () { return {

restrict:"AEC",

scope: { service: '@', username: '@' },

template: '<img src="http://avatars.io/' + '{{service}}/{{username}}" />' }; });</script>

<body ng-app="demo">

<ng-avatar service="twitter" username="leggetter" />

97 / 157

EmberJS

98 / 157

EmberJS<script src="js/jquery-1.10.0.min.js"></script>

99 / 157

EmberJS<script src="js/jquery-1.10.0.min.js"></script>

<script src="js/handlebars.js"></script>

100 / 157

EmberJS<script src="js/jquery-1.10.0.min.js"></script>

<script src="js/handlebars.js"></script>

<script src="js/ember.js"></script>

101 / 157

EmberJS<script src="js/jquery-1.10.0.min.js"></script>

<script src="js/handlebars.js"></script>

<script src="js/ember.js"></script>

<script> var App = Ember.Application.create();

App.EmAvatarComponent = Ember.Component.extend({

102 / 157

EmberJS<script src="js/jquery-1.10.0.min.js"></script>

<script src="js/handlebars.js"></script>

<script src="js/ember.js"></script>

<script> var App = Ember.Application.create();

App.EmAvatarComponent = Ember.Component.extend({

url: function () { return 'http://avatars.io/' + this.get( 'service' ) + '/' + this.get( 'username' ); }.property( 'username' , 'service' ) });</script>

103 / 157

EmberJS<script src="js/jquery-1.10.0.min.js"></script>

<script src="js/handlebars.js"></script>

<script src="js/ember.js"></script>

<script> var App = Ember.Application.create();

App.EmAvatarComponent = Ember.Component.extend({

url: function () { return 'http://avatars.io/' + this.get( 'service' ) + '/' + this.get( 'username' ); }.property( 'username' , 'service' ) });</script>

<script type="text/x-handlebars" id="components/em-avatar"> <img {{bind-attr src=url}} /></script>

104 / 157

EmberJS<script src="js/jquery-1.10.0.min.js"></script>

<script src="js/handlebars.js"></script>

<script src="js/ember.js"></script>

<script> var App = Ember.Application.create();

App.EmAvatarComponent = Ember.Component.extend({

url: function () { return 'http://avatars.io/' + this.get( 'service' ) + '/' + this.get( 'username' ); }.property( 'username' , 'service' ) });</script>

<script type="text/x-handlebars" id="components/em-avatar"> <img {{bind-attr src=url}} /></script>

<script type="text/x-handlebars"> {{em-avatar service="twitter" username="leggetter"}}</script>

http://jsbin.com/fexawujibe/2/edit?html,output105 / 157

ReactJS

106 / 157

ReactJS<script src="js/react.js"></script><script src="js/JSXTransformer.js"></script>

107 / 157

ReactJS<script src="js/react.js"></script><script src="js/JSXTransformer.js"></script>

<script type="text/jsx">var ReAvatar = React.createClass({ render: function() { return ( <img src={"http://avatars.io/" + this.props.service + "/" + this.props.username} /> ); }});

108 / 157

ReactJS<script src="js/react.js"></script><script src="js/JSXTransformer.js"></script>

<script type="text/jsx">var ReAvatar = React.createClass({ render: function() { return ( <img src={"http://avatars.io/" + this.props.service + "/" + this.props.username} /> ); }});

React.render( <ReAvatar service="twitter" username="leggetter" />, document.querySelector('re-avatar'));</script>

109 / 157

ReactJS<script src="js/react.js"></script><script src="js/JSXTransformer.js"></script>

<script type="text/jsx">var ReAvatar = React.createClass({ render: function() { return ( <img src={"http://avatars.io/" + this.props.service + "/" + this.props.username} /> ); }});

React.render( <ReAvatar service="twitter" username="leggetter" />, document.querySelector('re-avatar'));</script>

<re-avatar />

110 / 157

ReactJS<script src="js/react.js"></script><script src="js/JSXTransformer.js"></script>

<script type="text/jsx">var ReAvatar = React.createClass({ render: function() { return ( <img src={"http://avatars.io/" + this.props.service + "/" + this.props.username} /> ); }});

React.render( <ReAvatar service="twitter" username="leggetter" />, document.querySelector('re-avatar'));</script>

<re-avatar />

111 / 157

112 / 157

Polymer

<script src="webcomponentsjs/webcomponents.min.js"></script><link rel="import" href="polymer/polymer.html">

113 / 157

Polymer

<script src="webcomponentsjs/webcomponents.min.js"></script><link rel="import" href="polymer/polymer.html">

<polymer-element name="po-avatar" attributes="service username">

114 / 157

Polymer

<script src="webcomponentsjs/webcomponents.min.js"></script><link rel="import" href="polymer/polymer.html">

<polymer-element name="po-avatar" attributes="service username">

<template> <img src="http://avatars.io/{{service}}/{{username}}" /> </template>

115 / 157

Polymer

<script src="webcomponentsjs/webcomponents.min.js"></script><link rel="import" href="polymer/polymer.html">

<polymer-element name="po-avatar" attributes="service username">

<template> <img src="http://avatars.io/{{service}}/{{username}}" /> </template>

<script> Polymer('po-avatar', {}); </script></polymer-element>

116 / 157

Polymer

<script src="webcomponentsjs/webcomponents.min.js"></script><link rel="import" href="polymer/polymer.html">

<polymer-element name="po-avatar" attributes="service username">

<template> <img src="http://avatars.io/{{service}}/{{username}}" /> </template>

<script> Polymer('po-avatar', {}); </script></polymer-element>

<po-avatar service="twitter" username="leggetter" />

117 / 157

Polymer

<script src="webcomponentsjs/webcomponents.min.js"></script><link rel="import" href="polymer/polymer.html">

<polymer-element name="po-avatar" attributes="service username">

<template> <img src="http://avatars.io/{{service}}/{{username}}" /> </template>

<script> Polymer('po-avatar', {}); </script></polymer-element>

<po-avatar service="twitter" username="leggetter" />

118 / 157

Who's using? ...

Angular Directives

119 / 157

Who's using? ...

Angular DirectivesEmber Components

120 / 157

Who's using? ...

Angular DirectivesEmber ComponentsReact Components

121 / 157

Who's Building Componentised Web Apps now?Angular, Ember, Backbone, Knockout, React, Vue.js, Web Components with Polyfills, Polymer

...

128 / 157

Who's Building Componentised Web Apps now?Angular, Ember, Backbone, Knockout, React, Vue.js, Web Components with Polyfills, Polymer

...

You are!<ng-avatar service="twitter" username="leggetter" />

vs.

<my-avatar service="twitter" username="leggetter" />

129 / 157

Who's Building Componentised Web Apps now?Angular, Ember, Backbone, Knockout, React, Vue.js, Web Components with Polyfills, Polymer

...

You are!<ng-avatar service="twitter" username="leggetter" />

vs.

<my-avatar service="twitter" username="leggetter" />

That's the HOW130 / 157

Why Web Components are the future!

131 / 157

1. You're already building componentisedweb apps

If you're not, you probably should be

132 / 157

2. Trends/Alignment

133 / 157

Libraries

Alignment toward Web ComponentsAngular - DirectivesEmber - ComponentsKnockout - ComponentsPolymer - build upon Web ComponentsAngular 2...

134 / 157

http://guides.emberjs.com/v1.13.0/components/

‘ Ember's implementation of components hews asclosely to the Web Components specification aspossible. Once Custom Elements are widelyavailable in browsers, you should be able to easilymigrate your Ember components to the W3Cstandard and have them be usable by otherframeworks.

135 / 157

136 / 157

Have a Strategy

Will libraries update to use Web Components?Align with Web Components to make migrating easier

Split UI rendering and business logic

137 / 157

Browser Vendor Support

Google ✔Opera ✔Mozilla ✔Microsoft ✔Apple ✔

138 / 157

Dashboard Get Started Design Develop Publish Community WPDev Feedback

Microsoft Edge Developer

Welcome to the Microsoft Edge Developer Suggestion Box!

The Microsoft Edge team is looking for feature requests from the web developer and designer community. Categories

include (but certainly are not limited to) HTML, CSS, JavaScript, Performance, and Developer Tools. If you do not have

a suggestion at this time, you may still cast your vote for the features you would like to see supported!

This feedback will help us with planning and to better understand how web developers and designers are using the

platform. Top standards-based feature requests will also be copied over to http://dev.modern.ie/platform/status/, where

you can track its development status.

Note that this forum is intended for web platform feature suggestions. Related feedback channels:

Microsoft Edge application feedback (or use the Windows Feedback app in Windows Technical Preview)

Microsoft Edge feedback on Windows Phone

For specific bugs, please log an issue on the Connect site

Finally – a few guidelines and notes to keep things running smoothly:

1. Please be sure to search for ideas before entering a new suggestion. This helps to accrue the votes correctly.

2. Please enter a separate suggestion for each idea (avoid entering a suggestion with multiple ideas) and share

some information if possible on the most important scenarios that this enables for you. This helps to keep things

clear as to what people are voting for.

3. The items and rankings on this site are an important input, but do not reflect the final priority list for the Microsoft

Edge engineering team.

4. We will moderate suggestions made in the forum if they do not represent an actual feature request or are

inappropriate.

5. Please do not send any novel or patentable ideas, copyrighted materials, samples or demos which you do not

want to grant a license to Microsoft. See the Terms of Service for more information.

Microsoft Edge DeveloperPost a new idea…

All ideas

My feedbackAccessibility  4

CSS  59

Document Object Model (DOM)  7

Extensions  12

F12 Developer Tools  119

Graphics  21

HTML  49

JavaScript  61

Media  14

Miscellaneous  45

Networking  22

Performance  17

Security  1

New and returning users may sign in

Search 139 / 157

3. Demand

4. Encourages good softwaredevelopment

Component-based Development

140 / 157

Separation of Concerns<!doctype html><html> <head> <meta charset="utf-8"> <title>A new Gmail?</title> <meta name="description" content=""> </head> <body>

<header> <img src="img/logo.png" alt="Google Logo" /> <gmail-search /> <gmail-account-strip /> </header>

<gmail-side-bar> <nav is="gmail-labels"></nav> <gmail-contacts /> </gmail-sidebar> <main> <nav is="gmail-categories"></nav> <gmail-email-list /> </main>

<hangouts /> </body></html>

141 / 157

Encapsulation

Shadow DOM - Style & DOM encapsulationDoes NOT offer JavaScript protection

Hacky Custom Element

leggettertwitter

Don't click me!

142 / 157

Loose Coupling

Custom EventsElement API (interface)Or use existing messaging frameworks

143 / 157

Custom Events<script> var CustomEventPrototype = Object.create(HTMLElement.prototype); CustomEventPrototype.createdCallback = function() { // Build element ...

this.addEventListener('click', function() { var customEvent = new CustomEvent('cheese'); this.dispatchEvent(customEvent); }.bind(this)); };

// ...

144 / 157

Custom Events<script> var CustomEventPrototype = Object.create(HTMLElement.prototype); CustomEventPrototype.createdCallback = function() { // Build element ...

this.addEventListener('click', function() { var customEvent = new CustomEvent('cheese'); this.dispatchEvent(customEvent); }.bind(this)); };

// ...

var customEl = document.getElementById('my_custom_ev'); customEl.addEventListener('cheese', function() { alert('cheese fired!'); });</script>

<custom-event-ex id="my_custom_ev"></custom-event-ex>

145 / 157

Element API Attributes & Methods<script> CustomEventPrototype.startSpin = function() { this.img.classList.toggle('spin'); };

CustomEventPrototype.stopSpin = function() { this.img.classList.toggle('spin'); };

// ...

var spinEl = document.getElementById('spin_el'); spinEl.startSpin();

// ...

spinEl.stopSpin();</script>

<custom-event-ex id="spin_el"></custom-event-ex>

146 / 157

Supports Change

EncapsulationLoose Coupling

147 / 157

Encourage Reuse

Ease of SharingComposition

<link rel="import" href="https://some-cdn.com/my-avatar.html" />

148 / 157

High Cohesion

myavatar.html├── js/script.js├── css/styles.css└── img/bg.png

149 / 157

Problems? Solved in the future?

HTML ImportsVulcanize | HTTP2 | JavaScript modules

Shared scripts?CacheMultiple versions?

JavaScript scoping in v2Better cross-component communication?Allow <link> for CSS in Shadow DOM?

150 / 157

SummaryCustom Elements - Awesome

151 / 157

Summary

Custom Elements - Awesome

HTML Templates, Shadow DOM, HTML Imports- Native FTW

152 / 157

Summary

Custom Elements - Awesome

HTML Templates, Shadow DOM, HTML Imports- Native FTW

You can & are building componentised webapps now - Align

153 / 157

Summary

Custom Elements - Awesome

HTML Templates, Shadow DOM, HTML Imports- Native FTW

You can & are building componentised webapps now - Align

Trends & "best practice" ♥ Web Components

154 / 157

Summary

Custom Elements - Awesome

HTML Templates, Shadow DOM, HTML Imports- Native FTW

You can & are building componentised webapps now - Align

Trends & "best practice" ♥ Web Components

Web Components are the future!

155 / 157

Resourceshttp://webcomponents.org/https://www.polymer-project.orgWilson Page - The State of Web ComponentsChristian Heilmann - Web Components are an Endangered SpeciesAre we compontentized yet (podcast)Eric Bidelman's Google IO 2014 talkAngular MaterialGoogle Material DesignHTML Template ChooserIE UserVoice forumSource for these slideshttp://pusher.com - easily add realtime messaging to your apps

156 / 157

Why you should be using Web Components Now.And How.

Questions?

leggetter.github.io/web-components-now

PHIL @LEGGETTERHead of Developer Relations

157 / 157

Recommended