Selector.js

A small, fast, standard compilant, cross-browser implementation of an CSS3 Query Selector. Currently the Selector API (querySelectorAll) is only available in browsers based on WebKit (Safari and Chrome) and the soon to be released Firefox 3.1 and Internet Explorer 8. Similar selectors are also available in frameworks like base2, Dojo, Ext, jQuery, MooTools and Prototype. But, if you want to use query selection today without the bulky frameworks, our stand-alone selector is for you.

For fast queries, our implementation uses either DOM Level 3 XPath or pre-compiled JavaScript DOM traversal. The matched Element’s is always returned in a standard Array so iteration functions like forEach can be used (see Array.js). And to ease integration with other frameworks, the Selector class has hook functions to extend the result Element’s (patchElement) and Array (patchArray).

Selector.js supports all Simple selectors and Attribute selectors without namespace, all Combinators, Class selectors, ID selectors and all Pseudo-class selectors except the Dynamic pseudo-classes :hover and :visited, which isn’t possible with JavaScript/DOM. The other frameworks support a non-standard pseudo-selector :contains() and attribute compare operator !=, ours don’t.

Slickspeed benchmarks with comparison against other selector implementations, can be found here. Any call to the native querySelectorAll has been disabled. YUI selector is excluded, it’s one of the slower. NWMatcher and YASS are also excluded, without their result caching both are slow. Caching result is unrealible since DOMAttrModified events aren’t triggered when changing Element properties, it could also consume alot of memory. Some engines get a false speed boost by creating :nth- indices only once, ignoring that the node graph might change thus making any subsequent result incorrect. Most engines don’t support the -of-type pseudo selectors.

Intuitive usage, context node (document) optional:

// Normal constructor syntax:
new Selector('div > p').exec(document).forEach(function (e) {
  e.style.color = 'red';
});
// Or, the shorthand syntax:
Selector('div > p', document).forEach(function (e) {
  e.style.color = 'red';
});

Documentation

The generated online documentation can be found here.

To do

Changelog

Download

License

GNU Lesser General Public License <http://www.gnu.org/licenses/lgpl-3.0.txt>

Author

Henrik Lindqvist <henrik.lindqvist@llamalab.com>

Comments

  1. Incredible stuff - from the initial testing I've done with this, you share with Robert Nyman's DOMAssistant the distinction of being the only two JS APIs that produce the same results as native implementations - sizzle, yui, base2 and dojo all produce innaccurate data sets in some situations. You've even managed to avoid the bug of including pseudo-element selectors, which DOMAssistant has - so overall, I reckon this is the most accurate API available.

    I'm currently working on a CSS Utilities library (methods like getCSSStyleRules for a specific element) and this looks like it might be the perfect companion for browsers without a native selectors API (more thorough testing withstanding). I was using DOMAssistant before, but this is significantly smaller because it only does this one thing, and slightly more accurate.

    Kudos :)

    4. by brothercake on
    Thursday, 04 February 2010 at 06:52 GMT
  2. Great work!

    "if you want to use query selection today without the bulky frameworks, our stand-alone selector is for you."

    Yes, it's those pesky bulky frameworks isn't it :-) I too was looking for a way to get the good parts without the overhead of what I don't need. In the end I decided to build my own, modular framework called Packages JS, but it's still using the very simple (and incomplete / incorrect) getElementsBySelector from Simon Willison.

    Currently I am evaluating what selector engine should replace it but there is so much choice nowadays.. and there you come with yet another one to look at :)

    I will certainly have a good look at this one and will let you know if it made it into the final cut. Keep up the good work!

    -Stijn
    3. by Stijn on
    Friday, 07 August 2009 at 11:30 GMT
  3. Our engine only cache the compiled query patterns and :nth- indices if MutationEvents is available. Caching the query result elements is another matter, it could consume alot of memory, and in my testing I concluded that DOMAttrModified only trigger when using elem.setAttribute('name','value') not for elem.name='value'. In benchmarking it also hide the selector performance. The day when MutationEvents can be relied upon, all engines will use them, and then we're back comparing initial selection speeds once again.
    2. by Henrik Lindqvist on
    Sunday, 15 February 2009 at 02:20 GMT
  4. Henrik,
    good work ... for being a new 2009 project you are quite ahead.

    It is not clear if you reject caching as you say it is wrong in your explanation but then you use it in your source and you take advantage of that in the speed benchmarks.

    Caching is good if done in the correct way. Others have copied that bit and being unable to make it work at their advantage have discarded it and talk badly about it with no reasons.

    Also Mutation Events need to grow in browsers we can already get some profit from them.

    If you feature test them correctly at startup maybe you will also be able to take advantage of them if available. I retested "DOMAttrModified" in FF and Opera and seems to me they work.

    If you have different tests or results please tell.

    Have the best,

    Diego Perini
    1. by Diego Perini on
    Saturday, 14 February 2009 at 01:22 GMT

Comment

Enter the code visible here into the Code field
> Delete | Edit