X-Tag is a
+
lightweight, power-packed
+
Web Components library
+
that gets you there fast, and stays in its own lane.
+
+
+
+
+
+
+
Standard
+
Built on Web Components APIs
+
+
+
Efficient
+
Powerful features in 3k min/gzip
+
+
+
Pluggable
+
Plays nice with other libraries
+
+
+
+
+
+
What is X-Tag?
+
+
Originally developed at Mozilla, now supported by devs at Microsoft, X-Tag is an open source JavaScript library that wraps the W3C standard Web Components family of APIs
+
to provide a compact, feature-rich interface for component development. While X-Tag makes it easy to leverage all the Web Components APIs
+
(Custom Elements, Shadow DOM, Templates, and HTML Imports), it only requires Custom Elements API support to operate.
+
In the absence of the native Custom Elements APIs, X-Tag uses the same polyfill
+
Google's Polymer framework relies on. You can view our package options in the Builds section
+
The most important method in the X-Tag library is xtag.create(). The create function on the X-Tag object is what you'll use
- to create new custom element definitions, which can include things like lifecycle callbacks, attribute-linked getters/setters (accessors),
+
+ to create new custom element definitions that can be enhanced by using the built in lifecycle callbacks, attribute-linked getters/setters (accessors), rendering features, cached templating,
+
and event listeners. Here's what defining a simple custom element looks like with X-Tag:
+
+
Notice the class definition extends the class XTagElement. If you are not extending from a previously defined Custom Element,
+
you must always extend from the XTagElement class for X-Tag to properly construct your Custom Element definition. The tag name argument (and subsequent automatic
+
element registration) is optional - here's what it looks like without it, and how to register your element with a tag name separately:
+
+
+ Two advanced features of X-Tag you need to be aware of in detail are the pseudos and extensions API.
+
+ Here are examples:
+
+
+
+
Create your own Pseudo:
+
+
+
+
+
+ Once you create a pseudo and add it to the main xtag.pseudos object, as shown below,
+
+ you can then use it on any key of your custom element definition objects that has a
+
+ function as its value.
+
+
+
+
+
+
+
+xtag.pseudos.foo = {
+
+ onParse: function(ctor, property, args, fn){
+ /*
+ Description:
+
+ onParse is called when the pseudos specified in a declaration are being
+
+ compiled and wrapped around the function they are being applied to.
+
+ Parameters:
+
+ ctor: the Custom Element Class definition
+
+ property: property the pseudo is being applied to (ex: ping:foo, property = ping)
+
+ args: arguments from the pseudo definition (ex: prop:foo(1, 2), args = [1, 2])
+
+ fn: the function the pseudo is wrapping in the pseudo chain
+ */
+
+ },
+
+ onInvoke: function(node, obj){
+
+ /*
+ Description:
+
+ Invoke is called any time the pseudo-wrapped function is called. This is where
+
+ you perform whatever action you desire on the node or object the pseudo targets.
+
+ Parameters:
+
+ node: the element
+
+ obj: object composed of these properties: { fn: fn, args: args, detail: detail }
+
+ */
+
+ }
+
+};
+
+xtag.create("x-foo", class extends XTagElement{
+
+ "godzilla:foo"(){/* TODO APPLICATION LOGIC */}
+
+});
+
+
+
+
+
+
To an Extended Voyage
+
+
+
+ X-Tag uses the standard Custom Elements mechanism for inheritance: ES6 class extension. The return value of the create method is an X-Tag compiled ES6 class, which
+
+ can be itself extended either via generic ES6 class declaration, or by again passing it into create, if you wanted to add additional features to your new extended class
+
+ using X-Tag APIs.
+
+
+
+
+
+
+
+const Foo = xtag.create('x-foo', class extends XTagElement {
+
+ set 'foo::attr' (){ /* Handle foo attribute change */ }
+
+});
+
+
+
+Bar extends Foo {
+
+ bar (){ }
+
+}
+
+
+
+const Zaz = xtag.create('x-zaz', class extends Bar {
+
+ 'click::event' (){ /* do something when clicked */ }
+
+});
+
+
+
+
+
+
+
In the next sections you're going to hear about a few features that are delivered via two different types of modular extensibility systems the
+
library offers for imbuing your elements with advanced functionality. These two systems are called extensions and pseudos.
+
Both are different in their intent, scope of effect, range of capabilities. You will use them frequently in your Custom Element class definition
+
blocks, here's what they look like:
+
+
Notice how the alert method has a ::foo attached to it - this is an extension. Extensions are little modules you can created that are called
+
into service by tagging a property with :: + the name of the extension. Extensions are a sizable API of their own that let's you manipulate
+
far more than just the property they are tagged to. You can only use one extension per property.
+
+
+
+
The other API for adding custom functionality to components is called pseudos, which are seen above in the example property count:bar. When a pseudo is tagged to a property, the pseudo's
+
own function wraps the target function so that the pseudo is executed first, then the target, which receives its return value. You can chain pseudos, and
- they are compiled from left to right so that they left most pseudo function wrapper fires first, passing each function's return value down to the next, until
+
+ they are compiled from left to right so that the left most pseudo function wrapper fires first, passing each function's return value down to the next, until
+
finally the original target function is executed. You can see what this looks like in the above example property send::foo:bar:zaz.
+
+
+
+
There are separate guides for extensions and pseudos that talk about how to create and use your own, but for now just be aware that they are one of
+
the primary means the X-Tag library delivers its own features.
+
+
+
+
Create your own Extension:
+
+
+
+
Say Hello to Custom Attribute Accessors
+
+
+ Accessors are custom attributes linking to a corresponding pair of setters/getters, and X-Tag has a built-in extension that makes adding accessors to
+
+ your custom element definition stupid simple. To use this extension, add an ::attr modifier to one of your class definition properties.
+
+ This tells X-Tag to wire up a getter/setter to an HTML attribute of the same name. When attributes are linked to a getter/setter their gets, sets, and
+
+ state changes will be synced without having to write any additional code.
+
+
+
+
+ In addition to binding attributes the ::attr extension also allow you to declare a specific data type.
+
+
+
+
+
+xtag.create('x-foo', class extends XTagElement {
+
+ set 'maxVolume::attr' (value){
+
+ // X-Tag automatically maps camel cased getter/setter names to their
+
+ // dashed attribute equivalents. In this example, the `maxVolume`
+
+ // getter/setter pair maps to the `max-volume` attribute.
+
+ }
+
+});
+
+
+
+xtag.create('x-bar', class extends XTagElement {
+
+ '::template(true)' (){ return '<input />' }
+
+ set 'disabled::attr(boolean)' (value){
+
+ // The ::attr extended property links node.disabled to gets/sets of
+
+ // the disabled="" attribute. Because it is declared as a boolean,
+
+ // all values passed into its getter/setter will be a Boolean.
+
+ this.firstElementChild.disabled = value;
+
+ }
+
+});
+
+
+
+
+
+
+
+
Content is King
+
+
+
Many of the components you create will require child elements for structure and presentation. X-Tag includes a content templating
+
extension that makes this quick and easy. Simply add a ::template function to your component definition
- and return a string or ES6 Template String. In the example below, notice the true parameter being passed to the extension.
+
+ and return a string or ES6 Template String. In the example below, notice the true parameter being passed to the extension.
+
This tells the template extension to render the content immediately when an instance is created. If you don't want a template to render
+
automatically like this, don't pass anything to it.
+
+
+
+ The XTagElement's `render()` method is the work horse of the `template` `extension`and makes it possible to create feature rich application
+
+ parts. For more information regarding this check out the section.
+
+
+
+
+
+
xtag.create('x-frankenstein', class extends XTagElement {
+
'::template(true)' (){
+
return `<h2>I am Frankenstein</h2>
+
<span>I was created by a mad scientist</span>`
+
}
+
});
+
+
+
Manual Rendering of Templates
+
+
+
If you elect not to have your template automatically rendered when your component instances are created, you'll need to manually trigger render.
+
+
+
+
const Frank = xtag.create('x-frankenstein', class extends XTagElement {
+
name (){ return 'Frankenstein'; }
+
'::template' (){
+
return `<h2>I am ${this.name()}</h2>
+
<span>I was created by a mad scientist</span>`
- }
-});
+
+ }});
+
+
const FrankNode = new Frank();
+
FrankNode.render();
+
+
+
Multiple Templates
+
+
+
The template extension can be used multiple times within the same class definition block, which allows you to specify different templates
+
for use in the same component. The templates are cached and reference based on the property name you put in front of the ::template extension
+
token. To render your templates, simply pass the name of the template you want to use to the render function, as in the following example:
+
+
+
+
const Frank = xtag.create('x-frankenstein', class extends XTagElement {
+
'foo::template(true)' (){
+
return `<h2>My name is Frankenstein</h2>
+
<span>I work for a mad scientist</span>`
+
}
+
'bar::template' (){
+
return `<h2>My friends call me Frank</h2>
+
<span>I work for a mad scientist</span>`
+
}
+
});
+
+
const FrankNode = new Frank();
+
// Because the foo template indicated it was to be automatically rendered, its content is already present in your element instance.
+
FrankNode.render('bar');
+
// Calling the render function with the bar template name swaps out the current foo template content with the bar content.
+
-
-
Say Hello to Custom Attribute Accessors
-
- Accessors are custom attributes linking to a corresponding pair of setters/getters, and X-Tag has a built-in extension that makes adding accessors to
- your custom element definition stupid simple. To use this extension, add an ::attr modifier to one of your class definition properties.
- This tells X-Tag to wire up a getter/setter to an HTML attribute of the same name. When attributes are linked to a getter/setter their gets, sets, and
- state changes will be synced without having to write any additional code.
-
+
The Elements Render
+
+
+
+ The XTagElement's render() method is the work horse of the template extension. It get's attached to every X-Tag element that you create and can be reused for your own extensions and pseudos. Below is an example of using an event to initiate a mode accessor.
+
+
+
-
- You can also tell the accessor extension that type of accessor you are creating, and it will help by sanitizing values and modifying the gets/sets to
- match the behavior of the type you declare. I
-xtag.create('x-foo', class extends XTagElement {
- set 'maxVolume::attr' (value){
- // X-Tag automatically maps camel cased getter/setter names to their
- // dashed attribute equivalents. In this example, the `maxVolume`
- // getter/setter pair maps to the `max-volume` attribute.
+
+var _rendered = xtag.create( "x-mode", class extends XTagElement {
+
+ set 'mode::attr'(_mode) {
+
+ this.render(_mode);
+
+ return _mode;
+
}
-});
-xtag.create('x-bar', class extends XTagElement {
- '::template(true)' (){ return '<input />' }
- set 'disabled::attr(boolean)' (value){
- // The ::attr extended property links node.disabled to gets/sets of
- // the disabled="" attribute. Because it is declared as a boolean,
- // all values passed into its getter/setter will be a Boolean.
- this.firstElementChild.disabled = value;
+ get 'mode::attr'(){
+
+ return this.getAttribute("mode");
+
+ }
+
+ 'myModeSnippet::template'() {
+
+ return "
+
X-Tag provides a powerful event system you'll use often in developing your components.
+
We'll cover the basics here, and leave the more advanced features for a special tutorial dedicated to the topic.
-
-
- To add event listeners to your component (either native or custom events), you'll be using the event extension. To do so, add a property to your
- Custom Element definition that matches the name of the event you want to listen for, plus the ::event extension flag. When your class definition
- is processed by X-Tag's create method, the event extension will remove the property, add a listener using the supplied property name with the
- function you supplied as the handler.
-
-xtag.register('x-foo', {
- 'click::event': function(){
- // attaches a click listener that calls this function when
- // the user clicks an element inside the custom element
- },
- 'focus::event': function(){
- // attaches a focus listener that calls this function when
- // something inside your custom element is focused.
- }
-});
-
-
-
-
Gettin' Jedi with Pseudos
- One advanced feature of X-Tag you should be aware of right off the bat is the delegate pseudo.
- X-Tag features a function modifier system called pseudos which allows you to seamlessly wrap
- functions anywhere in your custom element defintion object (lifecycle callbacks, methods, accessors, and events)
- to extend their functionality. The delegate pseudo enables you to quickly add event delegation
- (filtering of event targets based on CSS expressions) to any event function you add to your component. Here's an example:
-
-xtag.register('x-foo', {
- content: '<input/>',
- events: {
- 'tap:delegate(input)': function(){
- // Perform an action only when the user taps on an
- // <input/> element within your component.
- }
- }
-});
-
+ To add event listeners to your component (either native or custom events), you'll be using the event extension. To do so, add a property to your
-
Create your own Pseudo:
+ Custom Element definition that matches the name of the event you want to listen for, plus the ::event extension flag. When your class definition
+
+ is processed by X-Tag's create method, the event extension will remove the property, add a listener using the supplied property name with the
+
+ function you supplied as the handler.
-
- Once you create a pseudo and add it to the main xtag.pseudos object, as show below,
- you can then use it on any key of your custom element definition objects that has a
- function as its value.
+
+
-xtag.pseudos.foo = {
- onParse: function(ctor, property, args, fn){
- /*
- Parse is called when the pseudos specified in a declaration are being
- compiled and wrapped around the function they are being applied to.
+xtag.register('x-foo', {
+
+ 'click::event': function(){
+
+ // attaches a click listener that calls this function when
+
+ // the user clicks an element inside the custom element
- ctor: the Custom Element Class definition
- property: property the pseudo is being applied to (ex: ping:foo, property = ping)
- args: arguments from the pseudo definition (ex: prop:foo(1, 2), args = [1, 2])
- fn: the function the pseudo is wrapping in the pseud chain
- */
},
- onInvoke: function(node, obj){
- /*
- Invoke is called any time the pseudo-wrapped function is called. This is where
- you perform whatever action you desire on the node or object the pseudo targets.
- node: the element
- obj: object composed of these properties: { fn: fn, args: args, detail: detail }
- */
- }
-};
-
+ 'focus::event': function(){
-
+ // attaches a focus listener that calls this function when
-
Inheritance
+ // something inside your custom element is focused.
-
- X-Tag uses the standard Custom Elements mechanism for inheritance: ES6 class extension. The return value of the create method is an X-Tag compiled ES6 class, which
- can be itself extended either via generic ES6 class declaration, or by again passing it into create, if you wanted to add additional features to your new extended class
- using X-Tag APIs.
-
+ }
-
-const Foo = xtag.create('x-foo', class extends XTagElement {
- set 'foo::attr' (){ /* Handle foo attribute change */ }
});
-Bar extends Foo {
- bar (){ }
-}
+
-const Zaz = xtag.create('x-zaz', class extends Bar {
- 'click::event' (){ /* do something when clicked */ }
-});
-
-
API Reference
+
+
xtag.create(TAG_NAME, DEFINITION)
+
+
+
Create and (optionally) register a Custom Element definition for use as a new tag in HTML markup or via DOM APIS.
+
+
+
+
+
Argument
+
Type
+
Description
+
+
+
TAG_NAME(optional)
+
String
+
+
The tag name you want to use when using your Custom Element (must contain a dash). When
+
this argument is passed, the Custom Element definition is automatically added to the document's Custom Element registry.
+
+
+
+
DEFINITION
+
Class
+
The class definition block for your Custom Element
+
Add a native, custom, or X-Tag library event listener to an element. The TYPE field also
+
accepts pseudo chains for even more powerful event handling.
+
+
+
+
+
Argument
+
Type
+
Description
+
+
+
ELEMENT
+
DOM element reference
+
+
The element you would like to attach an event listener to.
+
+
+
+
TYPE
+
String
+
+
The event name, with any event pseudos you may want to chain.
+
+
+
+
HANDLER
+
Function
+
+
The event handler you want called when the event occurs.
+
+
+
+
CAPTURE
+
Function
+
+
Boolean argument you can pass if you want the event to use capturing vs bubbling.
+
+
+
+
+
+
xtag.addEvent(myElement, 'tap:delegate(img)', function(event){
+
alert('An image element within myElement was just tapped');
+
});
+
+
+
+
+
xtag.addEvents(ELEMENT, OBJECT)
+
+
+
Add multiple native, custom, or X-Tag library event listeners to an element using one function.
+
Pseudo chains are avaliable for use in your event object keys.
+
+
+
+
+
Argument
+
Type
+
Description
+
+
+
ELEMENT
+
DOM element reference
+
+
The element you would like to attach the event listeners to.
+
+
+
+
OBJECT
+
Object
+
+
An object composed of multiple events - keys are event names, and values are the event handlers.
+
+
+
+
+
+
xtag.addEvents(myElement, {
+
'tap': function(event){
+
alert('myElement was just tapped');
+
},
+
'keypress:keypass(13)': function(event){
+
alert('The enter key was pressed, all other keys are blocked');
+
}
+
});
+
+
+
xtag.fireEvent(ELEMENT, NAME, OPTIONS)
+
+
+
Add a native, custom, or X-Tag library event listener to an element. The TYPE field also
+
accepts pseudo chains for even more powerful event handling.
+
+
+
+
+
Argument
+
Type
+
Description
+
+
+
ELEMENT
+
DOM element reference
+
+
The element you would like to attach an event listener to.
+
+
+
+
NAME
+
String
+
+
The event name you wish to fire on the target element.
+
+
+
+
OPTIONS
+
Object
+
+
The event options you want to use in firing your event. These include:
+
+
detail allows passage of custom data via the detail property of the event
+
bubbles specify whether the event bubbles - defaults to true
+
cancelable specify whether the event is cancelable - defaults to true