SlideShare a Scribd company logo
Why you should be using Web Components Now.
And How.
PHIL @LEGGETTER
Head of Developer Relations
1 / 157
2 / 157
3 / 157
What we'll cover
What are Web Components?
The State of Web Components
Componentised Web Apps Now
Why Web Components are the Future!
4 / 157
What are Web Components?
5 / 157
What are Web Components?
Custom Elements
HTML Templates
Shadow DOM
HTML 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 back
More than just markup
IMHO 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 building
Componentised 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 elements
30 / 157
Custom Elements - Lifecycle
createdCallback
attachedCallback
detachedCallback
attributeChangedCallback(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 → Native
Native benefits
Document fragment = lightweight
Inert 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 Scoping
Protection for all: Page and Element
Encapsulation
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 - Composition
team-pusher.html
57 / 157
HTML Imports - Composition
team-pusher.html
<link rel="import" href="my-avatar-import.html" />
58 / 157
HTML Imports - Composition
team-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 - Composition
team-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>
maxthelion
twitter
copypastaa
twitter
zimbatm
twitter
loicdumas
twitter
mdpye
twitter
olga_dukova
twitter
pawel_ledwon
twitter
hamchapman
twitter
LaurieWang_
twitter
swstagg
twitter
vivangkumar
twitter
willsewell_
twitter
davidrbiggs
twitter
leggetter
twitter
We're Hiring! pusher.com/jobs
62 / 157
Why Use HTML Imports?
Bundle JS/HTML/CSS → single URL
Basic dependency management
Sharing, 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 ownerDoc
var 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
is
Concerns around Accessibility
Point of Upgrade
When 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 of
HTML Imports. We expect that once JavaScript
modules ... is shipped, the way we look at this
problem will have changed.
75 / 157
Essential "State of" Reading
Wilson Page - The State of Web Components
Microsoft Edge Team - Bringing componentization to the web: An
overview 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 -0700
Message-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 components
4 results found
# Global 67.55%
U.K. 70.69%
IE / Edge Firefox Chrome Safari Opera iOS Safari
*
Opera Mini
* Android
Browser
* Chrome for
Android
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 parsed
but 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-support
82 / 157
Componentised Web Apps Now
83 / 157
Christian Heilmann - July 1st, 2015
‘When we asked the very captive and elite
audience of EdgeConf about Web Components,
nobody raised their hand that they are using them
in 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,output
105 / 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 Directives
Ember Components
120 / 157
Who's using? ...
Angular Directives
Ember Components
React Components
121 / 157
Who's using? ...
Angular Directives
Ember Components
React Components
KnockoutJS Components
122 / 157
Who's using? ...
Angular Directives
Ember Components
React Components
KnockoutJS Components
Vue.js Components
123 / 157
Who's using? ...
Angular Directives
Ember Components
React Components
KnockoutJS Components
Vue.js Components
Backbone Components
124 / 157
Who's using? ...
Angular Directives
Ember Components
React Components
KnockoutJS Components
Vue.js Components
Backbone Components
CanJS Components
125 / 157
Who's using? ...
Angular Directives
Ember Components
React Components
KnockoutJS Components
Vue.js Components
Backbone Components
CanJS Components
Famous Components
126 / 157
Who's using? ...
Angular Directives
Ember Components
React Components
KnockoutJS Components
Vue.js Components
Backbone Components
CanJS Components
Famous Components
Anything.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 HOW
130 / 157
Why Web Components are the future!
131 / 157
1. You're already building componentised
web apps
If you're not, you probably should be
132 / 157
2. Trends/Alignment
133 / 157
Libraries
Alignment toward Web Components
Angular - Directives
Ember - Components
Knockout - Components
Polymer - build upon Web Components
Angular 2...
134 / 157
http://guides.emberjs.com/v1.13.0/components/
‘Ember's implementation of components hews as
closely to the Web Components specification as
possible. Once Custom Elements are widely
available in browsers, you should be able to easily
migrate your Ember components to the W3C
standard and have them be usable by other
frameworks.
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 Developer
Post a new idea…
All ideas
My feedback
Accessibility  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 software
development
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 encapsulation
Does NOT offer JavaScript protection
Hacky Custom Element
leggetter
twitter
Don't click me!
142 / 157
Loose Coupling
Custom Events
Element 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
Encapsulation
Loose Coupling
147 / 157
Encourage Reuse
Ease of Sharing
Composition
<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 Imports
Vulcanize | HTTP2 | JavaScript modules
Shared scripts?
Cache
Multiple versions?
JavaScript scoping in v2
Better cross-component communication?
Allow <link> for CSS in Shadow DOM?
150 / 157
Summary
Custom 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 web
apps now - Align
153 / 157
Summary
Custom Elements - Awesome
HTML Templates, Shadow DOM, HTML Imports
- Native FTW
You can & are building componentised web
apps 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 web
apps now - Align
Trends & "best practice" ♥ Web Components
Web Components are the future!
155 / 157
Resources
http://webcomponents.org/
https://www.polymer-project.org
Wilson Page - The State of Web Components
Christian Heilmann - Web Components are an Endangered Species
Are we compontentized yet (podcast)
Eric Bidelman's Google IO 2014 talk
Angular Material
Google Material Design
HTML Template Chooser
IE UserVoice forum
Source for these slides
http://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 @LEGGETTER
Head of Developer Relations
157 / 157

More Related Content

PDF
Why you should be using Web Components. And How - DevWeek 2015
PDF
jQuery UI and Plugins
PPTX
Jquery Complete Presentation along with Javascript Basics
PDF
Creating GUI container components in Angular and Web Components
PPTX
Getting the Most Out of jQuery Widgets
PDF
Django workshop : let's make a blog
PDF
The Art of AngularJS in 2015 - Angular Summit 2015
PPT
Jquery ui
Why you should be using Web Components. And How - DevWeek 2015
jQuery UI and Plugins
Jquery Complete Presentation along with Javascript Basics
Creating GUI container components in Angular and Web Components
Getting the Most Out of jQuery Widgets
Django workshop : let's make a blog
The Art of AngularJS in 2015 - Angular Summit 2015
Jquery ui

What's hot (20)

PPTX
SharePoint and jQuery Essentials
PDF
Unlock the next era of UI design with Polymer
PDF
jQuery Loves Developers - Oredev 2009
PDF
Web Components & Polymer 1.0 (Webinale Berlin)
PPTX
Site optimization
PDF
jQuery Essentials
PDF
Building Universal Web Apps with React ForwardJS 2017
PPTX
Oracle Application Express & jQuery Mobile - OGh Apex Dag 2012
PDF
jQuery in the [Aol.] Enterprise
KEY
Simple Web Apps With Sinatra
 
PDF
jQuery for beginners
PDF
AtlasCamp 2015: Using add-ons to build add-ons
PDF
Angular Directives from Scratch
PDF
RequireJS & Handlebars
PDF
Practical HTML5: Using It Today
PDF
Yearning jQuery
KEY
jQuery Anti-Patterns for Performance & Compression
PDF
Introduction to javascript templating using handlebars.js
PDF
Advanced JQuery Mobile tutorial with Phonegap
PDF
Selenium再入門
SharePoint and jQuery Essentials
Unlock the next era of UI design with Polymer
jQuery Loves Developers - Oredev 2009
Web Components & Polymer 1.0 (Webinale Berlin)
Site optimization
jQuery Essentials
Building Universal Web Apps with React ForwardJS 2017
Oracle Application Express & jQuery Mobile - OGh Apex Dag 2012
jQuery in the [Aol.] Enterprise
Simple Web Apps With Sinatra
 
jQuery for beginners
AtlasCamp 2015: Using add-ons to build add-ons
Angular Directives from Scratch
RequireJS & Handlebars
Practical HTML5: Using It Today
Yearning jQuery
jQuery Anti-Patterns for Performance & Compression
Introduction to javascript templating using handlebars.js
Advanced JQuery Mobile tutorial with Phonegap
Selenium再入門
Ad

Similar to Why You Should be Using Web Components Right Now. And How. ForwardJS July 2015 (20)

PDF
HTML5 New and Improved
PPTX
JavaScript DOM - Dynamic interactive Code
KEY
An Introduction to HTML5
KEY
#NewMeetup Performance
PDF
TechDays 2013 Jari Kallonen: What's New WebForms 4.5
PDF
Real World Web components
PPTX
The Django Web Application Framework 2
PPTX
The Django Web Application Framework 2
PPTX
The Django Web Application Framework 2
PPTX
The Django Web Application Framework 2
PDF
The Complementarity of React and Web Components
PDF
Polymer - pleasant client-side programming with web components
KEY
Geek Moot '09 -- Smarty 101
PPTX
PDF
TurboGears2 Pluggable Applications
PDF
Web Components v1
KEY
关于 Html5 那点事
PPTX
Python Code Camp for Professionals 1/4
PPTX
lec 14-15 Jquery_All About J-query_.pptx
HTML5 New and Improved
JavaScript DOM - Dynamic interactive Code
An Introduction to HTML5
#NewMeetup Performance
TechDays 2013 Jari Kallonen: What's New WebForms 4.5
Real World Web components
The Django Web Application Framework 2
The Django Web Application Framework 2
The Django Web Application Framework 2
The Django Web Application Framework 2
The Complementarity of React and Web Components
Polymer - pleasant client-side programming with web components
Geek Moot '09 -- Smarty 101
TurboGears2 Pluggable Applications
Web Components v1
关于 Html5 那点事
Python Code Camp for Professionals 1/4
lec 14-15 Jquery_All About J-query_.pptx
Ad

More from Phil Leggetter (20)

PDF
An Introduction to AAARRRP: A framework for Defining Your Developer Relations...
PDF
How APIs Enable Contextual Communications
PDF
An Introduction to the AAARRRP Developer Relations Strategy Framework and How...
PDF
An Introduction to the AAARRRP Developer Relations Strategy Framework and How...
PDF
Contextual Communications: What, Why and How? Bristol JS
PDF
Real-Time Web Apps & .NET. What Are Your Options? NDC Oslo 2016
PDF
Real-Time Web Apps & .NET - What are your options?
PDF
The Past, Present and Future of Real-Time Apps and Communications
PDF
The Past, Present and Future of Real-Time Apps and Communications
PDF
What's the ROI of Developer Relations?
PDF
Real-Time Web Apps & Symfony. What are your options?
PDF
Real-Time Web Apps in 2015 & Beyond
PDF
Patterns and practices for building enterprise-scale HTML5 apps
PDF
Fed London - January 2015
PDF
How to Build Single Page HTML5 Apps that Scale
PDF
Realtime Web Apps in 2014 & Beyond
PDF
BladeRunnerJS Show & Tell
PDF
Testing Ginormous JavaScript Apps - ScotlandJS 2014
PDF
How to Build Front-End Web Apps that Scale - FutureJS
PDF
Using BladeRunnerJS to Build Front-End Apps that Scale - Fluent 2014
An Introduction to AAARRRP: A framework for Defining Your Developer Relations...
How APIs Enable Contextual Communications
An Introduction to the AAARRRP Developer Relations Strategy Framework and How...
An Introduction to the AAARRRP Developer Relations Strategy Framework and How...
Contextual Communications: What, Why and How? Bristol JS
Real-Time Web Apps & .NET. What Are Your Options? NDC Oslo 2016
Real-Time Web Apps & .NET - What are your options?
The Past, Present and Future of Real-Time Apps and Communications
The Past, Present and Future of Real-Time Apps and Communications
What's the ROI of Developer Relations?
Real-Time Web Apps & Symfony. What are your options?
Real-Time Web Apps in 2015 & Beyond
Patterns and practices for building enterprise-scale HTML5 apps
Fed London - January 2015
How to Build Single Page HTML5 Apps that Scale
Realtime Web Apps in 2014 & Beyond
BladeRunnerJS Show & Tell
Testing Ginormous JavaScript Apps - ScotlandJS 2014
How to Build Front-End Web Apps that Scale - FutureJS
Using BladeRunnerJS to Build Front-End Apps that Scale - Fluent 2014

Recently uploaded (20)

PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PPTX
Introduction to Artificial Intelligence
PDF
How Creative Agencies Leverage Project Management Software.pdf
PPTX
Online Work Permit System for Fast Permit Processing
PPTX
ManageIQ - Sprint 268 Review - Slide Deck
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PPTX
CHAPTER 12 - CYBER SECURITY AND FUTURE SKILLS (1) (1).pptx
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PPTX
ai tools demonstartion for schools and inter college
PDF
Understanding Forklifts - TECH EHS Solution
PDF
top salesforce developer skills in 2025.pdf
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PDF
Nekopoi APK 2025 free lastest update
PDF
System and Network Administration Chapter 2
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
Introduction to Artificial Intelligence
How Creative Agencies Leverage Project Management Software.pdf
Online Work Permit System for Fast Permit Processing
ManageIQ - Sprint 268 Review - Slide Deck
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
CHAPTER 12 - CYBER SECURITY AND FUTURE SKILLS (1) (1).pptx
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
Upgrade and Innovation Strategies for SAP ERP Customers
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
Which alternative to Crystal Reports is best for small or large businesses.pdf
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
2025 Textile ERP Trends: SAP, Odoo & Oracle
ai tools demonstartion for schools and inter college
Understanding Forklifts - TECH EHS Solution
top salesforce developer skills in 2025.pdf
Odoo Companies in India – Driving Business Transformation.pdf
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
Nekopoi APK 2025 free lastest update
System and Network Administration Chapter 2

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

  • 1. Why you should be using Web Components Now. And How. PHIL @LEGGETTER Head of Developer Relations 1 / 157
  • 4. What we'll cover What are Web Components? The State of Web Components Componentised Web Apps Now Why Web Components are the Future! 4 / 157
  • 5. What are Web Components? 5 / 157
  • 6. What are Web Components? Custom Elements HTML Templates Shadow DOM HTML Imports 6 / 157
  • 8. 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
  • 12. <Custom Elements /> Bring semantic markup back More than just markup IMHO the most important part of Web Components 12 / 157
  • 13. 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
  • 14. 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
  • 15. 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
  • 16. 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
  • 17. 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
  • 18. Tools, Tips & Tricks for building Componentised Web Apps 18 / 157
  • 19. <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
  • 20. Custom Elements <my-avatar service="twitter" username="leggetter" /> 20 / 157
  • 21. Custom Elements <my-avatar service="twitter" username="leggetter" /> <script> var MyAvatarPrototype = Object.create(HTMLElement.prototype); 21 / 157
  • 22. 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
  • 23. 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
  • 24. 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
  • 25. 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
  • 26. <my-avatar service="twitter" username="leggetter" /> <my-avatar service="instagram" username="leggetter" /> <my-avatar service="twitter" username="forwardjs" /> <my-avatar /> 26 / 157
  • 27. Custom Elements - Extending <img is="my-avatar-ext" service="twitter" username="leggetter" /> 27 / 157
  • 28. Custom Elements - Extending <img is="my-avatar-ext" service="twitter" username="leggetter" /> <script> var MyAvatarExtPrototype = Object.create(HTMLImageElement.prototype); 28 / 157
  • 29. 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
  • 30. 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 elements 30 / 157
  • 31. Custom Elements - Lifecycle createdCallback attachedCallback detachedCallback attributeChangedCallback(attrName, oldVal, newVal) 31 / 157
  • 32. 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
  • 36. 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
  • 37. 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
  • 38. 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
  • 39. 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
  • 40. 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
  • 41. Why native HTML Templates? Libraries → Native Native benefits Document fragment = lightweight Inert until cloned/used 41 / 157
  • 42. Shadow DOM DOM/CSS "scoping" / protection 42 / 157
  • 43. Shadow DOM - Already using it 43 / 157
  • 44. Shadow DOM - Problems it solves 44 / 157
  • 45. 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
  • 46. 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
  • 47. Shadow DOM - In Action Create ForwardJS 47 / 157
  • 48. 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
  • 49. 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
  • 50. 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
  • 51. 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
  • 52. 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
  • 53. Why Shadow DOM? DOM & CSS Scoping Protection for all: Page and Element Encapsulation 53 / 157
  • 54. HTML Imports Loading & Dependency Management 54 / 157
  • 55. 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
  • 56. 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
  • 57. HTML Imports - Composition team-pusher.html 57 / 157
  • 58. HTML Imports - Composition team-pusher.html <link rel="import" href="my-avatar-import.html" /> 58 / 157
  • 59. HTML Imports - Composition team-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
  • 60. HTML Imports - Composition team-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
  • 61. HTML Imports - Composition Demo <link rel="import" href="assets/team-pusher.html" /> <team-pusher></team-pusher> 61 / 157
  • 62. HTML Imports - Composition Demo <link rel="import" href="assets/team-pusher.html" /> <team-pusher></team-pusher> maxthelion twitter copypastaa twitter zimbatm twitter loicdumas twitter mdpye twitter olga_dukova twitter pawel_ledwon twitter hamchapman twitter LaurieWang_ twitter swstagg twitter vivangkumar twitter willsewell_ twitter davidrbiggs twitter leggetter twitter We're Hiring! pusher.com/jobs 62 / 157
  • 63. Why Use HTML Imports? Bundle JS/HTML/CSS → single URL Basic dependency management Sharing, Reuse, Composition 63 / 157
  • 65. 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
  • 66. importNode and NOT cloneNode for Template // Note: use ownerDoc var content = ownerDoc.querySelector( '#my-template' ); var clone = ownerDoc.importNode( content, true ); 66 / 157
  • 67. You can't <link> into the Shadow DOM <template> <link rel="stylesheet" href="path/to/style.css" /> </template> 67 / 157
  • 69. The State of Custom Elements is Concerns around Accessibility Point of Upgrade When HTMLElement is transformed into Custom Element 69 / 157
  • 70. The State of Templates ✔ 70 / 157
  • 71. The State of Shadow DOM <content select="tag" /> Declarative element content placement 71 / 157
  • 72. The State of Shadow DOM <content select="tag" /> Declarative element content placement element.createShadowRoot({ mode: 'closed' }); protecting shadowRoot 72 / 157
  • 73. 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
  • 74. The State of HTML Imports 74 / 157
  • 75. Firefox https://hacks.mozilla.org/2014/12/mozilla-and-web-components/ “Mozilla will not ship an implementation of HTML Imports. We expect that once JavaScript modules ... is shipped, the way we look at this problem will have changed. 75 / 157
  • 76. Essential "State of" Reading Wilson Page - The State of Web Components Microsoft Edge Team - Bringing componentization to the web: An overview of Web Components 76 / 157
  • 77. The State of Browsers 77 / 157
  • 79. Apple's updated feedback on Custom Elements and Shadow DOM From: Maciej Stachowiak <mjs@apple.com> Date: Mon, 20 Jul 2015 18:17:24 -0700 Message-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
  • 80. Can I use ? Settingsweb components 4 results found # Global 67.55% U.K. 70.69% IE / Edge Firefox Chrome Safari Opera iOS Safari * Opera Mini * Android Browser * Chrome for Android 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 parsed but not rendered until cloned. Current aligned Usage relative Show all 80 / 157 State of Browser Support
  • 81. All is not Lost 81 / 157
  • 82. Browsers - with Polyfills https://github.com/webcomponents/webcomponentsjs#browser-support 82 / 157
  • 83. Componentised Web Apps Now 83 / 157
  • 84. Christian Heilmann - July 1st, 2015 ‘When we asked the very captive and elite audience of EdgeConf about Web Components, nobody raised their hand that they are using them in real products. 84 / 157
  • 85. Componentised Web Apps Now - questions? Should native browser support stop us thinking about building componentised web apps? 85 / 157
  • 86. Componentised Web Apps Now - questions? Should native browser support stop us thinking about building componentised web apps? No! 86 / 157
  • 87. 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
  • 88. 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
  • 94. AngularJS <script src="js/angular.min.js"></script> <script> angular.module('demo', []) .directive('ngAvatar', function () { return { restrict:"AEC", scope: { service: '@', username: '@' }, 94 / 157
  • 95. 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
  • 96. 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
  • 97. 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
  • 102. 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
  • 103. 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
  • 104. 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
  • 105. 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,output 105 / 157
  • 108. 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
  • 109. 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
  • 110. 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
  • 111. 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
  • 114. 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
  • 115. 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
  • 116. 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
  • 117. 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
  • 118. 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
  • 119. Who's using? ... Angular Directives 119 / 157
  • 120. Who's using? ... Angular Directives Ember Components 120 / 157
  • 121. Who's using? ... Angular Directives Ember Components React Components 121 / 157
  • 122. Who's using? ... Angular Directives Ember Components React Components KnockoutJS Components 122 / 157
  • 123. Who's using? ... Angular Directives Ember Components React Components KnockoutJS Components Vue.js Components 123 / 157
  • 124. Who's using? ... Angular Directives Ember Components React Components KnockoutJS Components Vue.js Components Backbone Components 124 / 157
  • 125. Who's using? ... Angular Directives Ember Components React Components KnockoutJS Components Vue.js Components Backbone Components CanJS Components 125 / 157
  • 126. Who's using? ... Angular Directives Ember Components React Components KnockoutJS Components Vue.js Components Backbone Components CanJS Components Famous Components 126 / 157
  • 127. Who's using? ... Angular Directives Ember Components React Components KnockoutJS Components Vue.js Components Backbone Components CanJS Components Famous Components Anything.JS Components? 127 / 157
  • 128. Who's Building Componentised Web Apps now? Angular, Ember, Backbone, Knockout, React, Vue.js, Web Components with Polyfills, Polymer ... 128 / 157
  • 129. 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
  • 130. 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 HOW 130 / 157
  • 131. Why Web Components are the future! 131 / 157
  • 132. 1. You're already building componentised web apps If you're not, you probably should be 132 / 157
  • 134. Libraries Alignment toward Web Components Angular - Directives Ember - Components Knockout - Components Polymer - build upon Web Components Angular 2... 134 / 157
  • 135. http://guides.emberjs.com/v1.13.0/components/ ‘Ember's implementation of components hews as closely to the Web Components specification as possible. Once Custom Elements are widely available in browsers, you should be able to easily migrate your Ember components to the W3C standard and have them be usable by other frameworks. 135 / 157
  • 137. 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
  • 138. Browser Vendor Support Google ✔ Opera ✔ Mozilla ✔ Microsoft ✔ Apple ✔ 138 / 157
  • 139. 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 Developer Post a new idea… All ideas My feedback Accessibility  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
  • 140. 4. Encourages good software development Component-based Development 140 / 157
  • 141. 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
  • 142. Encapsulation Shadow DOM - Style & DOM encapsulation Does NOT offer JavaScript protection Hacky Custom Element leggetter twitter Don't click me! 142 / 157
  • 143. Loose Coupling Custom Events Element API (interface) Or use existing messaging frameworks 143 / 157
  • 144. 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
  • 145. 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
  • 146. 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
  • 148. Encourage Reuse Ease of Sharing Composition <link rel="import" href="https://some-cdn.com/my-avatar.html" /> 148 / 157
  • 149. High Cohesion myavatar.html ├── js/script.js ├── css/styles.css └── img/bg.png 149 / 157
  • 150. Problems? Solved in the future? HTML Imports Vulcanize | HTTP2 | JavaScript modules Shared scripts? Cache Multiple versions? JavaScript scoping in v2 Better cross-component communication? Allow <link> for CSS in Shadow DOM? 150 / 157
  • 151. Summary Custom Elements - Awesome 151 / 157
  • 152. Summary Custom Elements - Awesome HTML Templates, Shadow DOM, HTML Imports - Native FTW 152 / 157
  • 153. Summary Custom Elements - Awesome HTML Templates, Shadow DOM, HTML Imports - Native FTW You can & are building componentised web apps now - Align 153 / 157
  • 154. Summary Custom Elements - Awesome HTML Templates, Shadow DOM, HTML Imports - Native FTW You can & are building componentised web apps now - Align Trends & "best practice" ♥ Web Components 154 / 157
  • 155. Summary Custom Elements - Awesome HTML Templates, Shadow DOM, HTML Imports - Native FTW You can & are building componentised web apps now - Align Trends & "best practice" ♥ Web Components Web Components are the future! 155 / 157
  • 156. Resources http://webcomponents.org/ https://www.polymer-project.org Wilson Page - The State of Web Components Christian Heilmann - Web Components are an Endangered Species Are we compontentized yet (podcast) Eric Bidelman's Google IO 2014 talk Angular Material Google Material Design HTML Template Chooser IE UserVoice forum Source for these slides http://pusher.com - easily add realtime messaging to your apps 156 / 157
  • 157. Why you should be using Web Components Now. And How. Questions? leggetter.github.io/web-components-now PHIL @LEGGETTER Head of Developer Relations 157 / 157