An introduction to
Web Components
Soledad Penadés
@supersole
I work at Mozilla
essentially...
I help you build cool stuff on the web
or find out why you can't...
and nag people until you can.
So...
Web Components
huh?
Let's start by going back in time
Web 1.0
- Websites
- Cool websites of the day
- Homepages
- Animated GIFs!
- WEB RINGS!!
- View source
- Notepad
- Frontpage
- Java Applets
Web 1.5
- Passable CSS: Underlined text! Link colours! Border types!
- Passable JavaScript: Drop down menus! Chromeless windows! Pop ups! Snow animations!
- Lots of Flash :-(
Web 2.0
- DHTML
- XMLHttpRequest → AJAX
- JSON, JSONP
- APIs
- Mash ups
- Rich UIs
- Widgets!
- Calendars! Color pickers!
NoLess Flash!- JS frameworks and libraries: Prototype, Dojo, jQuery, yUI, mootools...
LOTS of plug-ins!
MASSIVE ecosystem, YAY!
- easy to add features to a project
- there's a plug-in for everything
- "designers can code"
- code reuse
- many different vendors
- but...
Maintenance pain
- globals / css bleeding all over the page
- various coding "standards" (or lack thereof)
- incompatible plugins (so you need to load 2+ libraries)
- subpar performance: life cycle not in sync with page render, changing the non-efficient CSS properties...
Also, cumbersome code
<div class="widget calendar ui theme-winter">
<div class="component-wrapper">
<div class="inner-content">
(ad nauseaum)
</div>
</div>
</div>
var componentWrapper
= document.createElement('div');
var innerContent
= document.createElement('div');
componentWrapper.appendChild(innerContent);
// ...
return componentWrapper;
// ...
calendarEl.appendChild(componentWrapper);
$("#datepicker")
.datepicker($.datepicker.regional["fr"]);
$("#locale").change(function() {
$("#datepicker").datepicker("option",
$.datepicker.regional[ $(this).val() ] );
});
Can we do better?
What if browsers made it easier to build modular, more encapsulated code?
What if we could teach new elements to the browser?
<x-calendar></x-calendar>
var calendar =
document.createElement('x-calendar');
var calendar =
document.querySelector('x-calendar');
calendar.nextMonth();
calendar.setLocale('fr');
Each instance of these new elements...
- is a DOM element
- Deals with building its DOM tree
- Behaves like other DOM elements
- Lives in the DOM tree with the rest of other elements
- Can be accessed and manipulated with DOM methods... or UI libraries
- Is also a JavaScript object
- ... so it can have methods!
How do we make this happen?
The pillars of Web Components
- Custom elements
- HTML templates
- Shadow DOM
- HTML imports
1. Custom elements
Teach the browser about a new type of element
document.register('web-bell', WebBellPrototype);
A custom element prototype
- at least extends HTMLElement.prototype
- defines lifecycle callbacks for element instances (created, attached...)
- defines methods
- defines getters, setters...
WebBell Prototype:
var WebBellPrototype =
Object.create(HTMLElement.prototype);
WebBellPrototype.createdCallback = function() {
this.innerHTML = '🔔';
};
2. HTML Templates
"Inert HTML chunks"
not live until you say so
<template id="row-template">
<tr>
<td><input .../></td>
<td><button .../></td>
</tr>
</template>
Creating rows on the fly
var tpl =
document.getElementById('row-template');
var table =
document.getElementById('form-table');
table.appendChild(tpl.content.cloneNode());
3. Shadow DOM
Or: you can see, but not touch this!
var shadow = node.createShadowRoot();
shadow.appendChild(otherNodes);
Shadow DOM in context
Shadow DOM:
Tricky yet powerful
- Creates a boundary around your element
- Superuseful for things such as players, calendars
- It is still in the same doc context (not an iframe)
- Many concepts and subtleties
- Nice tutorial
4. HTML imports
Include HTML documents in other HTML documents
or: "require() for the web"
<link rel="import" href="my-component.html">
my-component.html's <head>
<script src="my-component.js"></script>
<link rel="stylesheet" href="my-component.css">
(Rough) support overview
- Chrome, Opera: ALL
- Firefox: Behind a flag, ALL except HTML imports
- Safari: Templates
- Internet Explorer: ¯\_(ツ)_/¯
Not supported on every browser
but... polyfills!
webcomponents.js
- polyfills custom elements, HTML imports, Shadow DOM
- also WeakMap and Mutation Observers
Also webcomponents-lite.js
- polyfill custom elements and HTML imports only
Custom Elements are pretty safe to use right now!
A note of warning
Polyfills are NOT FREE
- They come at a cost (bandwidth, processing)
- Especially Shadow DOM polyfill!
- Be mindful and aware
What about Polymer? X-Tag?
Syntactic sugar to make vanilla web components less sour
I ❤️ BAD PUNS
- Built on top of the Web Components pillars
- ... or on the polyfills
- Not shipped with the browser!
X-Tag example
xtag.register('web-bell', {
extends: 'div',
lifecycle: {
created: function() {
this.innerHTML = 'BELL';
}
}
});
Declarative polymer example
<polymer-element name="web-bell" extends="div">
<template>
BELL
</template>
<script>
Polymer();
</script>
</polymer-element>
Imperative Polymer example
Polymer('web-bell', {
extends: 'div',
created: function() {
this.innerHTML = 'BELL';
}
});
There's also Bosonic
(but I haven't had time to look into it in detail yet)
- using a mixture of webcomponents.js polyfills and their own
- compatible down to IE9
Which one is better?
- All are nice libraries...
- but you need the library the component was built with to instantiate them
- and we're back to the jQuery/Moo situation
- Yet once you instantiate them, they are just DOM elements! Yay!