Fork Download

X-Tag

Rocket fuel for component development


  • Standard

    Built on Web Components APIs
  • Efficient

    Powerful features, just 5k gzipped
  • Pluggable

    Plays nice with other libraries

What is X-Tag?

X-Tag is a Microsoft supported, open source, JavaScript library that wraps the W3C standard Web Components family of APIs to provide a compact, feature-rich interface for rapid component development. While X-Tag offers feature hooks for all Web Component APIs (Custom Elements, Shadow DOM, Templates, and HTML Imports), it only requires Custom Element support to operate. In the absence of native Custom Element support, X-Tag uses a set of polyfills shared with Google's Polymer framework. You can view our package options in the Builds section


Browser Support

Edge (all versions and devices), Internet Explorer 9+
Firefox (all versions, devices, and platforms)
Chrome (all versions, devices, and platforms), Android 4+ stock browser
Safari Mac, Safari iOS 5+
Opera 11+ (all devices and platforms)

Time for a demo

Here's a nifty ‹x-clock› component to help you get a sense of what it's like to create Web Components with X-Tag. As you can see, there's a tap event attached to the element that lets you start and stop time - but be careful, stopping time is serious business, you don't want to cause a chain reaction that unravels the very fabric of the space-time continuum.

xtag.register('x-clock', { lifecycle: { created: function(){ this.start(); } }, methods: { start: function(){ this.update(); this.xtag.interval = setInterval(this.update.bind(this), 1000); }, stop: function(){ this.xtag.interval = clearInterval(this.xtag.interval); }, update: function(){ this.textContent = new Date().toLocaleTimeString(); } }, events: { tap: function(){ if (this.xtag.interval) this.stop(); else this.start(); } } });

Docs

Table of Contents

Getting Started

Registration - Where it All Begins

The most important method in the X-Tag library is xtag.register(). The register function on the X-Tag object is what you'll use to create new custom element definitions, which can include things like lifecycle callbacks, attibute-linked getters/setters (accessors), and event listeners. Here's what defining a simple custom element looks like with X-Tag:

xtag.register('x-frankenstein', { lifecycle:{ created: function(){ alert("Look! It's moving. It's alive!"); } } });

Content is King

For many of the components you create, you'll want to insert various elements into them for structure and presentation purposes. X-Tag provides some awesome features to help you with this. The primary method for adding content to your component with X-Tag is the content property of your component registration defintion. The content property accepts both a simple HTML string, or a comment string within a function to enable multiline HTML snippets. Below are examples of what each variant looks like in practice.

Simple string:

xtag.register('x-frankenstein', { content: '‹h2›My name is Frank‹/h2›' + '‹span›I work for a mad scientist‹/span›' });

Multi-line string:

xtag.register('x-frankenstein', { content: function(){/* ‹h2›My name is Frank‹/h2› ‹span›I work for a mad scientist‹/span› */} });

Meet the Lifecycle Callbacks

There are four lifecycle callbacks you will rely on to develop your components. Here's an example of what each looks like when specified in an element definition:

xtag.register('x-foo', { lifecycle:{ created: function(){ alert('I fire when an ‹x-foo› is CREATED'); }, inserted: function(){ alert('I fire when an ‹x-foo› is INSERTED to the DOM'); }, removed: function(){ alert('I fire when an ‹x-foo› is REMOVED from the DOM'); }, attributeChanged: function(attrName, oldValue, newValue){ alert('I fire when an ATTRIBUTE is CHANGED on an ‹x-foo›'); } } });

Adding Methods to the Mix

Your custom elements will likely need some of their own, unique methods to provide the functionality you desire. X-Tag makes method addition a snap, just add a methods object to your top-level xtag.register() definition object and include your methods within it - here's what it looks like:

xtag.register('x-shouter', { lifecycle:{ created: function(){ this.shout('WHY AM I YELLING?'); } }, methods: { shout: function(message){ alert(message); } } });

Say Hello to Accessors

X-Tag has built-in features to deal with attributes, setters, getters, and link them all together to provide a common interface. To use these features, you first add an accessors object to the top level of your xtag.register() definition object. Within this object you can add keys names that will be made available as getters/setters, as seen below. By adding the key attribute, to an accessor, it tells X-Tag to link the setter/getter with the corresponding HTML attribute of the same name. When attributes are linked to a getter/setter, their gets, sets, and state will remain in sync without having to write any additional code.

The `attribute` property of an accessor has a few options you can use to change behavior and perform advanced syncing to other parts of your component. Some of these advanced options include `boolean`, `property`, and `validate`, which are detailed in the examples below.

xtag.register('x-foo', { content: '‹input /›', lifecycle:{ created: function(){ this.xtag.input = this.querySelector('input'); } }, accessors: { disabled: { // The `attribute` property links node.bar gets/sets to the bar="" attribute attribute: { // Including the boolean property turns this into a boolean attribute/setter boolean: true, // The property field allows you reflect changes down to a cached node. // Notice the input element is cached to the `input` property in `created` property: 'input' }, get: function(){ // do something when the getter is accessed }, set: function(value){ // act on the value being passed to the setter } } } }); xtag.register('x-bar', { accessors: { // X-Tag utomatically maps camelcased accessor setter names to their // dashed attribute equivalents. In this example, `limitedCount` maps // to the `limited-count` attribute. limitedCount: { attribute: { // Allows you to validate values passed to your accessor validate: function(val){ return val < 10 ? val : 10; } }, get: function(val){ // do something when the getter is accessed }, set: function(value){ // act on the value being passed to the setter } } } });

The DL on Events

X-Tag provides an insanely 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.

The first thing you'll need to do to attach events to your component is add an events object to the top level of your xtag.register() definition object. The keys of this object are the names of the events you wish to attach to your custom element. In the example below you'll see a familiar, native event name, focus, and a couple that X-Tag provides to make life easier: tap and move. These are just two of the custom events X-Tag provides that unify, optimize, and simplify common event interactions across platforms and devices. In the case of tap and move, X-Tag is unifying the mouse and touch equivalents of these events - have a look:

xtag.register('x-foo', { events: { focus: function(){ // perform an action when the user focuses something // within your custom element. }, tap: function(){ // perform an action when the user taps your custom // element via a mouse click or touch input. }, move: function(){ // perform an action when the user moves their // mouse click or finger (touch) over your element } } });

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. } } });

Create your own Pseudo:

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 defintion objects that has a function as its value.

xtag.pseudos.example = { onAdd: function(){ /* This function is fired once when the base function is added to the target object. For instance: If you added an event with xtag.addEvent(someNode, 'tap:example', fn), the onAdd function of the 'example' pseudo would be fired once when the event is first attached to the element 'someNode'. */ }, onRemove: function(){ /* This is basically the opposite of the onAdd function above. With onRemove, you can clean up whatever you may have done in your onAdd or action function invocations. */ }, action: function(pseudo, event) { /* This function is fired each time the pseudo chain is fired. Pseudo actions are fired in the order they are chained, meaning the in the pseudo 'toggle:log:example', the action function for the 'log' pseudo would fire first, then the 'example' action and finally the base function 'toggle' they are chained to. */ } };

Inheritance

X-Tag uses the standard Custom Elements API for inheritance. Custom elements can inherit from standard DOM elements by using the extends property.

xtag.register('x-checkbox', { extends: 'input', lifecycle: { created : function(){ this.type = "checkbox"; } } });

To use the extended standard DOM element the is syntax is need.

<input is="x-checkbox"> </input>

Extending custom elements:

To extend custom elements, you need to use the the prototype property. Keep in mind that when any of the properties of the custom element is overwritten, it gets added to an execution queue. When accessed, the base property will be executed first and then the rest of the queue will be accessed. For this cases the is syntax is not needed.

var xSpan = xtag.register('x-span', { content: '', methods: { render() { // some render logic }, }, }); xtag.register('x-money-span', { prototype: xSpan.prototype, methods: { render: function() { // xSpan render logic gets executed first // x-money-span render logic is executed next }, } });

API Reference

xtag.register(NAME, DEFINITION)

Define and register a new custom element. The example below shows test values for each of the top-level definition objects.

Argument Type Description
NAME String The custom element's tag name (must contain a dash)
DEFINITION Object An object containing the various features your custom element will utilize
xtag.register('x-foo', { content: '‹input/›', lifecycle:{ created: function(){}, inserted: function(){}, removed: function(){}, attributeChanged: function(){} }, methods: { someMethod: function(){} }, accessors: { someAccessor: { // links to the 'some-accessor' attribute attribute: {}, set: function(){}, get: function(){} } }, events: { tap: function(){}, focus: function(){} } });

xtag.query(ELEMENT, SELECTOR)

Wrapper for querySelectorAll that always returns a true JavaScript Array. This is handly for ensuring selections are easily iterable with standard JS Array functions, like forEach and map.

Argument Type Description
ELEMENT DOM element refrence A reference to the DOM element you wish to query
SELECTOR String The CSS selector you would like to query the element with
var itemArray = xtag.query(document.body, 'ul li');

xtag.queryChildren(ELEMENT, SELECTOR)

Query only the direct children of an element with a provided selector.

Argument Type Description
ELEMENT DOM element refrence A reference to the DOM element you wish to query.
SELECTOR String The CSS selector string you would like to test for matches against the element's direct children.
var onlyChildButtons = xtag.queryChildren(myToolbar, 'button');

xtag.createFragment(CONTENT)

Generates a document fragment from a string, list of nodes, or a multi-line comment string.

Argument Type Description
CONTENT
  • String
  • Multi-line function comment
Pass in a string or function with a multi-line comment string of HTML, and a Document Fragment will be created from the contents.
var fragFromString = xtag.createFragment('‹div›Hello World!‹/div›'); var fragFromFunction = xtag.createFragment(function(){/* ‹header›Hello‹/header› ‹section›I'm a multi-line HTML fragment‹/section› ‹footer›Goodbye‹/footer› */});

xtag.addEvent(ELEMENT, TYPE, HANDLER)

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.
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
xtag.fireEvent(myElement, 'show', { detail: { x: 123, y: 456 } });
Guides
Getting Started
API Reference
register query queryChildren addEvent addEvents fireEvent

Builds

Install from NPM:

npm install x-tag


Install from Bower:

bower install x-tag-core


Download the build that works best for you:

Community

  • Coming Soon

Overview Docs Builds Community
Supported by
Microsoft