Skating with Web Components
Trey Shugart
DogeScripter, Atlassian
What are web components?
Web Components are a collection of standards that allow the building, and use of, reusable components made with HTML, CSS and JavaScript.
- Templates
- Shadow DOM
- HTML Imports
- Custom Elements
What are web components?
- Chrome OS keyboard
- Chrome OS media player
- GitHub's <time is="relative-time"> element
What are Web Components?
<div> soup anyone?
What are Web Components?
<hangout-contacts>
<hangout-contact
src="dont-eat-the-yellow-snow.png"
name="Frank Zappa"
last-message="Frank: Freak Out!"
></hangout-contact>
...
</hangout-contacts>
Polymer
- Implemented through polyfills
- Expands on it to provide data-binding and template expressions
- Support is mostly usable in IE10, Safari 6 and Safari Mobile
- Not small, 223k min (Platform + Polymer)
- Not production ready
x-tags
- Mozilla
- Custom Elements through a proprietary API
- Adds convenience
- Nothing polyfilled by default
- IE9+
- 31.8k min
skate.js
Skate
- Me
- Loosely follows the custom element spec
- Simple ShadowDOM-style templating
- Custom Element and HTML Imports polyfill in development
- Binds components using classes, attributes and tags
- 6.7k min
- Already in production!
Skating Classes
You've got some tabs
<ul class="tabs">
<li><a href="#tab1">Tab 1</a></li>
<li><a href="#tab2">Tab 2</a></li>
</ul>
But they only work on DOMReady
jQuery(function ($) {
$('.tabs').tabs();
});
Just wrap it with Skate!
skate('tabs', {
type: skate.types.CLASS,
ready: function (element) {
jQuery(element).tabs();
}
});
skating attributes
Input or textarea needs to clear when ESC is pressed
<input type="text" data-clear-on-esc>
// or
<textarea data-clear-on-esc></textarea>
Create an attribute component!
skate('data-clear-on-esc', {
type: skate.types.ATTR,
events: {
keyup: function (element, e) {
if (e.keyCode === 27) {
element.value = '';
}
}
}
});
Skating Elements
You want an auto-complete element
<auto-complete url="some/service.json"></auto-complete>
Add a tag binding
var AutoComplete = skate('auto-complete', {
type: skate.types.TAG,
events: {
'keyup input[type="text"]': function (element, e) {
showSomeSuggestions(
element.getAttribute('url'),
e.target.value
);
}
},
template: '<input type="text">'
});
Element constructors!!
var autoComplete = new AutoComplete();
autoComplete.setAttribute('url', 'some/service.json');
What You Get
Class, attribute and tag bindings
skate('my-component', {
// binds to classes, attributes and tags by default
type: skate.types.ANY
});
- ANY - class, attr or tag
- TAG
- ATTR
- CLASS
- NOTAG - class or attr
- NOATTR - class or tag
- NOCLASS - attr or tag
What You Get
Congruent API
Except:
// Component does not support custom elements.
var MyComponent = skate('my-component', {
type: skate.types.NOTAG
});
// Will throw an exception!
var myComponent = new MyComponent();
What You Get
Lifecycle callbacks
skate('my-component', {
ready: calledBeforeVisible,
insert: calledAfterVisible,
remove: calledAfterRemoval
});
* ready(), if specified, prevents element from showing until done
Async ready()
ready: function asyncReady (element, done) {
doSomethingAsync().then(done);
}
* Specifying "done" makes callback async
What You Get
Prototype properties / methods
skate('my-component', {
prototype: {
someMethod: function () {
// "this" refers to the element
console.log(this);
}
}
});
Somewhere else...
document.getElementById('my-component').someMethod();
What You Get
Awesome attribute API
skate('my-component' {
attributes: function handleAnyAttributeChange (element, change) {
console.log(change);
// type: 'insert, update or remove',
// name: 'attribute-name',
// newValue: 'new attribute value, undefined if just removed',
// oldValue: 'old attribute value, undefined if just inserted'
}
});
or
attributes: {
'attribute-name': handleInsertAndUpdate
}
or even
attributes: {
'attribute-name': {
insert: handleInsert,
update: handleUpdate,
remove: handleRemove
}
}
What You Get
Events
skate('my-component', {
events: {
click: function handleClick (element, e) {
...
}
}
});
Event delegation, Backbone style!
events: {
'click .delegate[selector]': function handleDelegateClick (element, e) {
// use `e.target` to get the delegate
}
}
What you get
ShadowDOM-style templating by default
skate('my-component', {
template: '<article>' +
'<h2><content select=".heading"></content></h2>' +
'<section><content></content></section>' +
'</article>'
});
HTML before
<my-component>
<span class="heading">My Heading</span>
<p>First paragraph.</p>
<p>Second paragraph.</p>
</my-component>
HTML after
<my-component>
<article>
<h2><span class="heading">My Heading</span></h2>
<section>
<p>First paragraph.</p>
<p>Second paragraph.</p>
</section>
</article>
</my-component>
What You Get
Custom templating
skate('data-handlebars', {
template: function (element) {
var template = Handlebars.compile(element.innerHTML);
element.innerHTML = template({
title: 'Handlebars',
body: 'However, you can use anything you want: React, Mustache, Jade, etc.'
});
}
});
HTML before
<div data-handlebars>
<h1>{{ title }}</h1>
<p>{{ body }} </p>
</div>
HTML after
<div data-handlebars>
<h1>Handlebars</h1>
<p>However, you can use anything you want: React, Mustache, Jade, etc.</p>
</div>
Thanks!
github.com/skatejs/skatejs
Skating with Web Components
By Trey Shugart
Skating with Web Components
- 7,874