Skip navigation.

exploreopera

| Help

Sign up | Help

Opera Core Concerns

Official blog for Core developers at Opera

avatar

Selectors API

, ,

The Selectors API specification, currently being worked on within the WebAPI working group at the W3C, defines DOM APIs designed to make it possible to select elements within the document using Selectors. This simple, yet powerful API has the potential to make working with the DOM faster and easier. If you’re familiar with CSS, you will be familiar with Selectors and these APIs should be easy to learn.

For example, to select all the em and strong elements within the document, you can use this.

document.querySelectorAll("em, strong");

To see how much easier this is compared with traditional APIs, consider this example HTML fragment:

<ul id="fruits">
  <li><input type="checkbox" name="fruit" value="apples"> Apples</li>
  <li><input type="checkbox" name="fruit" value="oranges"> Oranges</li>
  <li><input type="checkbox" name="fruit" value="bananas"> Bananas</li>
  <li><input type="checkbox" name="fruit" value="grapes"> Grapes</li>
</ul>

After the user has filled out the form containing those check boxes, suppose you want to get the list of all the checked items. Using traditional APIs, this would require obtaining a list of all the input elements and iteratively checking which ones were checked.

var fruits = document.getElementById("fruits");
var checkboxes = fruits.getElementsByTagName("input");
var list = [];
for (var i = 0; i < checkboxes.length; i++) {
  if (checkboxes[i].checked) {
    list.push(checkboxes[i]);
  }
}

Using these new APIs, the operation can be reduced to a single line of code!

var list = document.querySelectorAll("#fruits input:checked");

This returns a node list containing all the input elements that were checked by the user. Your script can then perform any operation you like with them.

We have been working on an implementation of these APIs recently and support has been included within the recently released Acid 3 build.

There are two new methods introduced: querySelector() and querySelectorAll(). The former returns the first matching element within the tree, and the latter returns a collection of all matching elements as a NodeList. The current editor’s draft specification defines that the methods are available on the Document, Element and DocumentFragment nodes. However, our implementation currently only supports it on the Document and Elements nodes.

The querySelector() method is useful for situations where only the first matching element is needed, and is designed to be more efficient than the alternative querySelectorAll() method in such cases.

For example, the following form control and javascript function could be used to validate an email address. For simplicity, this uses the validity APIs from Web Forms 2.0. If support for legacy user agents is required, a more appropriate validity check could be written. The querySelector() method is used to obtain the correct element for outputting the appropriate error message, or clearing it when it is valid.

The JavaScript:

function validateEmail(evt) {
  var ctrl = event.target;
  var parent = ctrl.parentNode;
  var errMsg = parent.querySelector(".error");

  // Validate form control value
  if (!ctrl.validity.valid) {
    errMsg.innerHTML = "Invalid email address."
  } else {
    errMsg.innerHTML = "";
  }
}

The HTML fragment:

<p><input type="email" name="email" onchange="validateEmail();">
   <strong class="error"></strong></p>

Our implementation also partially supports the namespace resolver features, allowing you to work with mixed namespace documents and select elements based on their namespace. Consult the specification for more information on the NSResolver object.

You can try out these examples for yourself in the recently released Acid 3 Gogi Build which is available for Windows and Linux.

Welcome to Core Concerns!

Comments

avatar
They should have done it this way in the first place! Very powerful tech, this. It's just too bad that it won't see widespread use until the other browsers catch up, and who knows when that will be.

Great work.

By GreyWyvern, # 22. May 2008, 13:34:09

avatar
This functionality is already available in a cross-browser fashion from many javascript frameworks like jQuery, Prototype, extJs etc.

While it would be nice to have this integrated to browser, i don't see this really catching on in the near future, especially since IE is not so fast at implementing new standards...

By d4n3, # 22. May 2008, 16:36:51

avatar
@d4n3 : AFAIK, the IE team is implementing support for this in IE8

By virtuelvis, # 22. May 2008, 18:30:46

avatar
The thing is that frameworks like JQuery, Prototype, etc. will be able to use the native query selector instead of the js one they've cobbled together from strings and rubber bands. That means speedy scripting for Opera/Safari and not-quite-so-speedy for FF/IE, but at least working.

By peroo, # 22. May 2008, 18:33:06

avatar
The advantage of a native implementation is also that more selectors will be supported beyond the limitations of the existing JS libraries, as well as improved performance.

By lachlan.hunt, # 22. May 2008, 20:01:10

avatar
Great stuff!
I hope JS libraries will implement DOM queries in standard compliant way, so if native support will be available JS library will use it.
At that moment I know only one example of such library: base2.

Prototype, jQuery, YUI, ExtJS, DOMAssistant doen't have any clues about querySelector.
Mootools had unaccepted path for this with such reason for dissaproval:
We wont add it just yet, because
1) That version of queryselectorall is nothing compared to mootools selectors, in terms of validity.
2) Your patch would break custom pseudoselectors.
3) That version of webkit isnt yet released.

By FataL, # 22. May 2008, 20:37:39

avatar
It's great to see Opera work on this as well. I just hope nobody jumps the gun and implements this prematurely. That would be horrible.

To clarify things: WebKit implemented it and it's available at least in 3.1
IE8b1 implemented this as well, but without Namespaces, as far as I know.
Mozilla plans to do this for the 1.9.1 release of Gecko which is planned for end of this year.
And now Opera, this is really great. It seems to see the light very soon and will get Web Apps a better performance.

By Zake, # 22. May 2008, 21:04:23

avatar
This is very similar to xpath except less verbose. I wouldn't be surprised if internally this api relied on xpath. Currently most libraries (at least prototype and jquery) turn the query selectors into xpath for all browsers that support it (read: not ie). For those who are unaware, document.selectSingleNode is to document.querySelector as document.selectNodes is to document.querySelectorAll. Both xpath functions are merely a simplistic interface to document.evaluate.

Examples:
Selectors API:
document.querySelectorAll("em, strong");

Xpath:
document.selectNodes('//em|//strong');
or
document.selectNodes('//*[name() = "em" or name() = "strong"]');


Selectors API:
var errMsg = parent.querySelector(".error");

Xpath:
var errMsg = parent.selectSingleNode('//*[contains(concat(" ", @class, " "), " error ")]')


Using these new APIs, the operation can be reduced to a single line of code!
var list = document.querySelectorAll("#fruits input:checked");
This is where selectors outshine xpath. Xpath can only find the elements whom have <input ... checked="checked" /> in the source. However, clicking a checkbox nor changing elem.checked changes/adds the checked property to the element. So that will be most useful. Thanks for the article. Glad the core is getting some love.

By fearphage, # 23. May 2008, 12:45:47

avatar
Yay! My wish is coming true! Thanks guys, great stuff.

By Fyrd, # 23. May 2008, 13:17:59

avatar
This is great, but I have one major concern:

The API doesn't mention what level of CSS it should support as a minimum.
The problem becomes obvious when you have a javascript version of Selectors API like the ones you have in jquery, prototype, moo tools and others, and you want to accelerate them with Selectors API if present.
All of these libraries have supported a couple of CSS 3 stuff for a long time, and some of them are really popular because of their use cases in javascript:
*:odd ( get every odd child pr matched tag )
*:even ( get every even child pr matched tag )
*:child(2) ( get child 2 pr matched tag )
*:last-child (get last child of every matched tag )
The first three maps perfectly with :nth-child :
*:nth-child(odd)
*:nth-child(even)
*:nth-child(2)

My point is that the Specification should demand full CSS 2.1 support and some of the most needed child selectors in CSS3 like nth-child and last-child ( maybe also nth-type, but haven't used that much so wouldn't know the value of it ). And IE8 is at the moment the only browser that is holding this back from being the case.

As for xpath, Selector API is from the benchmarks I have seen around, a lot faster. So I don't think it uses xpath internally.

By andré1, # 23. May 2008, 19:13:40

Write a comment

You must be logged in to write a comment. if you're not a registered member, please sign up.