Why You Should be Using Web Components Right Now. And How. ForwardJS July 2015
-
Upload
phil-leggetter -
Category
Software
-
view
179 -
download
2
Transcript of Why You Should be Using Web Components Right Now. And How. ForwardJS July 2015
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>© 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/[email protected]" />
<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 <[email protected]> Date: Mon, 20 Jul 2015 18:17:24 -0700Message-id: <[email protected]> To: public-webapps <[email protected]>
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
All is not Lost
81 / 157
Browsers - with Polyfills
https://github.com/webcomponents/webcomponentsjs#browser-support82 / 157
Componentised Web Apps Now83 / 157
Christian Heilmann - July 1st, 2015
‘ When we asked the very captive and eliteaudience of EdgeConf about Web Components,nobody raised their hand that they are using themin real products.
84 / 157
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 DirectivesEmber Components
120 / 157
Who's using? ...
Angular DirectivesEmber ComponentsReact Components
121 / 157
Who's using? ...
Angular DirectivesEmber ComponentsReact ComponentsKnockoutJS Components
122 / 157
Who's using? ...
Angular DirectivesEmber ComponentsReact ComponentsKnockoutJS ComponentsVue.js Components
123 / 157
Who's using? ...
Angular DirectivesEmber ComponentsReact ComponentsKnockoutJS ComponentsVue.js ComponentsBackbone Components
124 / 157
Who's using? ...
Angular DirectivesEmber ComponentsReact ComponentsKnockoutJS ComponentsVue.js ComponentsBackbone ComponentsCanJS Components
125 / 157
Who's using? ...
Angular DirectivesEmber ComponentsReact ComponentsKnockoutJS ComponentsVue.js ComponentsBackbone ComponentsCanJS ComponentsFamous Components
126 / 157
Who's using? ...
Angular DirectivesEmber ComponentsReact ComponentsKnockoutJS ComponentsVue.js ComponentsBackbone ComponentsCanJS ComponentsFamous ComponentsAnything.JS Components?
127 / 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