Fork me on GitHub

HTML(.js)

Befriend the DOM!

HTML is a small, powerful way for you to enjoy working directly with the DOM.   HTML.min.js (~2.7kb, gzip)

Intuitive

HTML lets you navigate, manipulate and use the DOM with intuitive, readable, consistent code.

Powerful

HTML's functions enable you to flexibly use all native DOM features with brevity, clarity, and more power than ever.

Extensible

HTML has a modular design that is easy to extend, adapt or customize to meet your needs.

See our F.A.Q.!


API

HTML document.documentElement

The global HTML is the actual document root element and all element tags queried via the dot operator are descendants.

HTML.tag... Element|Array

HTML allows you to access document elements via their tag name. If multiple elements of the same tag exist, a proper array of elements is returned; otherwise, an Element is returned. Only the first node returned is "HTML-ified" (prepared for further chaining).

HTML.body.header; // returns header element.
HTML.body.header.textContent = "A Better Header!";

HTML.query(selector) Element|Array 0.10.0

HTML.query acts as a proxy for querySelectorAll and returns the selected element(s).

HTML.query("#example"); // single node returned

HTML.query(".example"); // Array of nodes returned if more than one, otherwise a node

HTML.query("#example").h1.em; // chain on, man.

HTML.tag....query(selector) Element|Array 0.10.0

You can, of course, use query on any "HTML-ified" element(s) to search only the children thereof.

HTML.body.div.query(".example"); // contextual search!

HTML.query(selector limit) Element|Array 0.11.0

HTML.query acts as a proxy for querySelector or querySelectorAll (as appropriate) and returns no more than the specified number of selected element(s).

HTML.query("#example", 1); // single node or empty Array returned

HTML.body.query(".example", 5); // returns a single node if only one, otherwise an Array of 0-5 nodes

HTML.tag....each(callback(element,index,array)) Element|Array

Use a the selected element(s) within a closure. Returns the element(s) it was called on.

HTML.query('li').each(function(el, i, all) {
	el.textContent = "Item " + (i+1) + " of " + all.length;
}); // returns li elements

HTML.body.ul.each(function(ul) {// each works on single nodes too
	if (ul.matches('.sunny')) {
	    ul.li.style.background = "blue";
	}
}); // returns the ul

HTML.tag....each(property , arguments...) Element|Array

Get, set, or invoke the specified property of the selected element(s). Returns either an array of retrieved/returned values or the element(s) it was called on.

var items = HTML.body.ul.li;
var texts = items.each('textContent'); // returns array of strings

items.each('id', 'item${i}');// sets the id of each element (replaces ${i} with index)

items.each('click');// calls 'click()' on each element, returns original items

items.each('classList.add', 'foo');// adds 'foo' class to each item's classList, returns original items

HTML.tag....all(property , includeSelf) Element|Array

Recurses through the DOM tree via the specified property, gathering the nodes as it goes to be returned. This makes it easy to gather all an elements ancestors, descendants, next/previous siblings, etc.

var focused = document.activeElement.all('parentElement', true);// returns Array of elements containing the current focus, including the active element.

var first = HTML.body.div.only(0);
var nextAll = first.all('nextElementSibling'); // returns Array of all subsequent sibling elements.

var all = HTML.body.all('children'); // all descendants of the  tag

HTML.tag....only(selector|index|filter|slice , endSlice) Element|Array

When you want to narrow down a selection, only allows you to easily filter that list by selector, index, slice, or filtering function.

var items = HTML.body.ul.li; // all li elements

items.only('.highlighted'); // subset that matches selector

items.only(3).textContent = "Fourth li element!"; // index (single element)

items.only(-1).id = 'last'; // negative index works too

items.only(function(o,i){ return !(i%2); }); // filter function returns even elements

items.only(3, 9).each('add', 'button');// specific slice of elements

HTML.tag....add(tag|Node|Array) Element|Array

This automatically adds the specified tag or node (or list thereof) to the element(s) on which it was called.

HTML.body.add('div'); // returns a newly added div element

HTML.body.add('div').add('h1'); // returns the new h1 element (with div parent)

HTML.head.add(document.createElement('div'));

HTML.body.add([node1, node2, [ul1, ul2]]); // yummy recursive adding

HTML.tag....add('emmet-abbr') Element|Array

The standard HTML.js artifact comes with the "emmet" extension, which lets you use emmet abbreviations to add elements to the DOM. This extension supports most emmet features, except grouping and numbering. Those may be added later.

HTML.body.add('ul>li{list item text}*10');

//Use in conjuction with only
HTML.body.add('ul>li{item}*10')
	.only(function(li,i){ return i%2; })
	.each('classList.add','odd');

HTML.tag....remove() undefined|Array

Removes the specified node (or list thereof). Some browsers provide this natively for elements, for the few who don't this polyfills the gap and enables use of it on arrays of elements. When called on a list, it returns the list of deleted items.

HTML.query('.foo').remove();

HTML.ify(Element|Array) Element|Array

When you get element(s) from an interface not under HTML's supervision, call this on it to give it HTML properties and functions.

if (!('each' in node)) {
	HTML.ify(node);
}
node.each(function(el){ console.log(el, ' is your friend!'); });

HTML._other Node|Array

On any element, you may access the non-element nodes via ._other

var nodes = HTML.body.section._other;
var text = nodes.only(function(node){ return node.nodeType == 3; });

HTML._.fn.name = function;

Use this to create your own plugins that extend the DOM, but remember to tread lightly! HTML is about learning and using the DOM, not obscuring it beneath foreign interfaces.

HTML._.fn.hide = function() {
	return this.each('style.display', 'none');	
};
HTML.query('.foo').hide();

HTML._.resolve[alias] = property; 0.10.0

Occasionally, the verbosity of the DOM can, like any friend, become tiresome. You may create property aliases for each.

HTML._.resolve['-class'] = 'classList.remove';
HTML._.resolve['+class'] = 'classList.add';
HTML.query('.foo').each('-class', 'foo').each('+class', 'bar');

HTML._.resolve.insert = 'insertAdjacentHTML';
HTML.query('.neighbor').each('insert', 'afterend', '<span>Hello.</span>');

<html data-html-reference="reference"> 0.10.1

Rumor has it some people find 'HTML' annoying to type. If you prefer another name, you can configure it globally by setting a data-html-reference attribute on the root element. This, of course, doesn't apply to those loading via a tool like AMD or Browserify where HTML is not automatically set as a reference in the window.

&lt;html data-html-reference="html"&gt;&lt;
&lt;script&gt;
  html.query('example-element').each('example-attribute','example value');
&lt;/script&gt;

FAQ

Another jQuery wannabe, eh?

Definitely not. jQuery and friends always hide the DOM from you. This used to be partly to protect you from it, but now it's just out of habit. HTML's intent is to directly expose and enhance the DOM. The DOM of the present is not the anemic mess it was even a few short years ago; protection from it is more pointless with every passing month. In fact, more than being unnecessary, that "protection" is often stunting your education. HTML is here to lubricate the process of learning what is really happening, and maybe throw in a few original features to sweeten the deal.

Why should i use HTML instead of jQuery?

Asking this question is kinda like saying that a very large swiss-army knife is the only tool you'll ever want. Some people prefer to collect specialized tools. Some people don't like jQuery's wrapper obscuring the riches of the native DOM. Some people just like doing it this way. There's probably other reasons out there too, but hopefully that's enough to move on to more useful questions.

Why give it the same name as, well, "HTML"?

Succint, self-documenting code is the ideal, and a self-descriptive name is also a great ward against feature creep. This HTML javascript library will not be about AJAX or JSON or CSS. It is about interacting with your document's HTML structure in javascript. To wit, it just fits.

Isn't 'HTML.query' a lot more to type than '$'?

Yeah, but jQuery and clones kinda have a lock on that $ shortcut. Lucky for you, it's easy to make:
window.$ = HTML.query.bind(HTML);

Which browsers does HTML support?

Only the modern ones: Firefox, Chrome, Safari, Opera, IE9+ and the like. With some judicious polyfilling you might get IE8 to support everything but the dot-traversal syntax, but i'd argue there are better solutions.

Isn't extending the DOM a bad idea?

Only if you care to prop up the diminishing market share of IE6/7/8. For those working on the future, smart DOM extension is no longer to be feared.

How does the DOM traversal work?

By defining lazy object getter functions for child tags. Again, we only do it lazily, on objects you access via this library, to keep the impact small.

Aren't those long dot-traversal chains a bad idea when pages are so dynamic?

Yes, same rules as with all DOM selector interfaces. Use query() with classes and ids when doing "whole page" work. Dot-traversal is best for small, well-defined node structures.

Functions that return either elements or arrays are bad. I saw it get ugly once!

Different contexts, different code, different techniques. Here's the rules for doing things right with HTML: 1) If you are certain you have one result (e.g. HTML.query('#foo'), list.only(1) or within each(callback) or only(filter) functions), then you can call DOM methods directly. 2) In all other situations, use HTML's functions (especially each('property')) to abstract the difference between one or more elements. You don't need to write branching code (like plain DOM) or use a wrapper object (like jQuery) to do that abstraction; HTML's functions do it superbly.

Hey, this is like Voyeur.js...

This began as a fork but became much different and much more. Adrian Cooney's delightful DOM traversal concept remains in play, as do the essentials of his lovely demo and site.

I have a suggestion, where do I put it?

I do a happy dance when you create an issue on Github.