Skip to content
Sly is a turbocharged, cross-browser, library-agnostic JavaScript class for querying DOM documents using CSS3 selectors.
Branch: master
Clone or download
Pull request Compare This branch is 63 commits ahead, 1311 commits behind subtleGradient:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.

Sly - The JavaScript Selector Engine

Sly is a turbocharged, cross-browser, library-agnostic JavaScript class for querying DOM documents using CSS3 selectors.


  • Pure and powerful JavaScript matching algorithm for fast and accurate queries
  • Extra optimizations for frequently used selectors and latest browser features
  • Works uniformly in DOM documents, fragments or XML documents
  • Utility methods for matching and filtering of elements
  • Standalone selector parser to produce JavaScript Object representations
  • Customizable pseudo-classes, attribute operators and combinators
  • Just 3 kB! (minified and gzipped, 8 kB without gzip)
  • No dependencies on third-party JS libraries, but developers can override internal methods (like getAttribute) for seamless integration.
  • Code follows the MooTools philosophy, respecting strict standards, throwing no warnings and using meaningful variable names


Sly is all about selectors and matching them against elements.

Basic Syntax

engine = Sly(selector);
result = engine.method(...);

Arguments: selector (required) is a CCS selector.

Returns: The Sly instance, holding all the methods for querying and matching elements (instances are cached).

Shorter notation without variable:

result = Sly(selector).method(...);

Sly generics

Every method is also accessible in a different notation:

result = Sly.method(selector, ...);


found =, parent)

// is the same as

found = Sly(selector).search(parent);

// and to make it clear:

bool = new Sly(selector).match(someElement);

// is the same as

bool = Sly.match(selector, someElement);

Querying with search and find

elements = Sly(selector).search([parent]);

Arguments: parent (optional) the document or an element.

Returns: The method a JavaScript Array of elements. It will be empty if there was no match.


// Finds all div blocks
blocks ='div');

// Finds all anchors with `href` attribute that starts with `"http://"`
anchors ='a[href^="http://"]');

// Finds all list item that are direct descendants of the list item with id `"navigation"`
items ='ul#navigation > li');

// Finds all heading elements
heads ='h1, h2, h3, h4, h5, h6');

// Finds all odd rows in all tables with the class `"zebra"`
rows ='table.zebra tr:odd');

// Finds something and looks really complex
inputs ='form[action$=/send/] label~span+input[type=text]:first-child');

Single result

You can also reduce the queried result to a single element:

element = Sly.find(selector[, parent]);

Returns: The first matched element or null.


Descendants can be at the beginning of a selector, using the optional parent element as reference.

parent = Sly.find('#content')

// Finds every second descendant children of parent
children ='> :odd', parent);

// Finds the next slibing of parent, if its an anchor
anchors = Sly.find('+ a', parent);

// Finds all slibings from parent that are `div` blocks
blocks = Sly.find('~div', parent);

// Finds all descendant children, of all descendant children, of all descendant children, of all descendant children of parent
items = Sly.find('>>>>', parent);


Sly.Custom provides more extensions for

  • Combinators like < (parent element), ^ (previous slibing) or <^±^> (The-Combinator-Smilie)
  • Attribute operators like [title/="^Item \\d+$"] (regular expression match)
  • Pseudo-classes like :hidden and :enabled

Matching with match and find

bool = Sly(selector).match(element);

Argument: element (required) to check against.

Returns: true if the element matches the selector properties, otherwise false.

bool = Sly(selector).filter(elements);

Argument: element (required) to check against.

Returns: A new Array of elements, containing all the elements that matched the selector properties.

Parsing with parse

list = Sly(selector).parse([plain]);

Arguments: If plain (optional) is true, the parser will not call Sly.compute to add additional search and match methods to the representation.

Returns: Splits a sequence of CSS selectors into their JavaScript representation, an Array of Objects for every selector. This is only done once, afterwards the created Array is reused in search, match, etc.

Parsed example:

example = 'ul#my-list > li.selected a:nth-child("odd"), a[href^=#]';
parsed = Sly.parse(example);

Returns an Array with 4 Objects, one for every selector in the 2 groups:

// Properties with empty `Arrays` (e.g. `classes`) `false` or `null` are left out in this scheme
		tag: 'ul',
		id: 'my-list',
		first: true
		tag: 'li',
		classes: ['odd'],
		combinator: '>'
		tag: 'a',
		pseudos: [{
			name: 'nth-child',
			value: 'odd'
		combinator: ' ',
		last: true
		tag: 'a',
		attributes: [{
			name: 'href',
			operator: '=',
			value: '#'
		first: true,
		last: true

Some Specifications

  • The parser does not validate the sequence
  • The universal selector "*" is not saved to the tag property
  • Values for pseudo-classes or attributes can be wrapped in "" or '', only required for complex values or better readability

The Tale About The "Why"

I started with the first version of Sly as MooTools branch in February 2008. Later on, the branch was forgotten, since Valerio did a great job to optimise selectors for the 1.2 release. When discussions about fast and accurate selector engines came up again in the last months, I recovered and updated my old obsession to check it against the new kids on the block. The results were surprising, so I added documentation and specs to release it to the public.

Sly was, and still is, just an exercise, relaxation for an optimisation addict like me. I hope it inspires other developers to incorporate it completely or take apart the source so that it is used within their libraries or work.


  • Support for more pseudo-classes like :root, but do people really need them?
  • Support for namespaces, e.g. ns|tag-name

Licence & Copyright


This documentation is released under a Attribution-NonCommercial-ShareAlike 3.0 License.


Valerio Proietti & MooTools contributors - Idea of modular combinator and pseudo filters - Code for several pseudo filters - Slickspeed benchmark framework Steven Levithan - Improved Sly.parse RegExp Diego Perini - Research on querySelectorAll and browser quirks - Patches for Sly.parse expression - Combined tests from jQuery and Prototype Thomas Aylott & Slick contributors - Idea of using regular expressions in attribute filter. John Resig & jQuery/Sizzle contributors - Browser feature/quirks detection - Additional pseudo filters - Extensive Unit Tests Sam Stephenson & Prototype contributors - Extensive Unit Tests Alan Kang & JSSpec contributors - JSSpec BDD framework

You can’t perform that action at this time.