15:00
Web Components
Why you're already an expert
Why?
Components Today
<link rel="stylesheet" type="text/css" href="my-widget.css" />
<script src="my-widget.js"></script>
<div data-my-widget />
$(function() {
$('[data-my-widget]').myWidget();
});
div.innerHTML = '<div data-my-widget />'
$(div).find('[data-my-widget]').myWidget(); // again...
<div data-my-widget>
<div class="my-widget-foobar">
<input type="text" class="my-widget-text" />
<button class="my-widget-button">Go</button>
</div>
</div>
Web Components
<link rel="import" href="my-widget.html" />
<my-widget />
div.innerHTML = '<my-widget />';
<my-widget>
#document-fragment
<div>
<input type="text" />
<button>Go</button>
</div>
</my-widget>
- Custom Elements
- Shadow DOM
- Template Element
- HTML Imports
- CSS Decorators
DOM Elements
You're already an expert
Elements can be instantiated with markup
<input type="text" />
Elements can be instantiated with JS
var input = document.createElement('input');
el.innerHTML = '<input type="text" />';
Elements are instances
input instanceof HTMLInputElement; // true
div instanceof HTMLDivElement; // true
Elements perform their own initialisation
el.innerHTML = '<input type="text" value="foobar" />';
el.querySelector('input').value; // "foobar"
Elements can respond to attribute changes
input.setAttribute('value', 'Foobar')
input.value; // "Foobar"
Elements can have hidden internal DOM structures
<input type="date" />
dateInput.children.length; // 0
Elements have access to child elements
<select>
<option>1</option>
<option>2</option>
<option>3</option>
</select>
Elements can have their own private styles
(Notice you don't need to do this)
<link rel="stylesheet" type="text/css" href="calendar.css" />
Elements can provide style hooks to their internals
dialog::backdrop {
background: black;
}
Custom Elements
Register a new custom element
var MyElement = document.register('my-element');
Custom elements can be instantiated with markup
<my-element />
Custom elements can be instantiated with JS
document.createElement('my-element');
el.innerHTML = '<my-element />';
new MyElement();
Custom elements are instances
document.create('my-element') instanceof MyElement; // true
Custom elements can perform their own initialisation
document.register('my-element', {
prototype: Object.create(HTMLElement.prototype, {
createdCallback: {
value: function() {
this.innerHTML = '<h1>ELEMENT CREATED!</h1>';
}
}
})
});
Custom elements can respond to attribute changes
document.register('my-element', {
prototype: Object.create(HTMLElement.prototype, {
attributeChangedCallback: {
value: function(attr, oldVal, newVal) {
this.innerHTML = '<h1>ATTRIBUTE CHANGED!</h1>';
}
}
})
});
Shadow DOM
Custom elements can have hidden internal DOM structures
createdCallback: {
value: function() {
var shadow = this.createShadowRoot();
shadow.innerHTML = "<h1>SHADOW DOM!</h1>";
}
}
Custom elements have access to child elements
<my-element>
<i>hello</i>
<i>world</i>
</my-element>
createdCallback: {
value: function() {
var shadow = this.createShadowRoot();
shadow.innerHTML = 'The <i> tags are: <content select="i" />';
}
}
Encapsulated Styles
Custom elements have encapsulated styles by default
shadow = this.createShadowRoot();
shadow.innerHTML =
"<style>span { color: green; }</style>" +
"<span>I'm green</span>";
<my-element />
<span>I'm not green</span>
Custom elements can provide style hooks to their internals
createdCallback: {
value: function() {
var shadow = this.createShadowRoot();
shadow.innerHTML = 'Hello <em part="world">World</em>';
}
}
my-element::part(world) {
color: green;
}
- Simple
- Consistent
- Reusable
- Encapsulated
- Composable