TL;DR: There are several properties that hold space delimited values - the class="" attribute used by CSS is the most well understood/widely encountered… Working with them as simple attributes is painful, so we created .classList which is a DOMTokenList that is reflective on the class attribute. This is great, but the more I run into similar cases because of increased focus on A11Y (several aria attributes are similar) the more I wish that we had access to DOMTokenLists for those… I’m proposing (and providing a prollyfil linked in the article) that we add an accessor method in the DOM API
Which returns you a DOMTokenList that you can work with… Full details in the linked piece.
The more one works with the accessibility tree, the more one realizes that it stands apart from other object models. If I’m understanding correctly, this strives takes the pain out of cross-OM communication. Brilliant. One of the biggest pain points I see today. (See also forthcoming work on CSS Generated Content Module)
Would love something like that as a standard (+polyfill). Using jQuery we end up abusing the class attribute because .removeClass, .addClass and .hasClass and .toggleClass are just easier to work with. Element.classList reproduces this same problem.
This borders on bikeshedding, but doesn’t element.asTokenList suggests that it would return the element itself as a token list (which doesn’t make much sense). Perhaps this would be better:
On a different topic, is there an issue tracker for your prollyfill? It has a few issues.
var el = document.createElement('p');
el.setAttribute('class', ' a b c ');
var no_classList = el._asTokenList('class');
console.log( el.classList.length ); // 3
console.log( no_classList.length ); // 12
console.log( '' + el.classList ); // " a b c "
console.log( '' + no_classList ); // "[object Object]"
Array.prototype.join.call(el.classList) // "a,b,c"
Array.prototype.join.call(no_classList) // ",,,,,,,,,,,"
el.classList[ el.classList.length - 1 ] // "c"
no_classList[ no_classList.length - 1 ] // undefined
Perhaps you could create a _DummyDOMTokenListPrototype object and use Object.create(_DummyDOMTokenListPrototype) and perhaps protect the length property too if possible.
By the way, a standalone function (method of Document?) like parseTokenList() or createTokenList() would probably be more useful since we then could parse any token string, not just a value of an attribute of an existing element.
It may also be useful, but I would argue that not more so because the token list isn’t generated and disconnected, it remains connected…
// gets the token list
var tokenList = document.body.classList;
// uses setAttribute after the token list is created...
document.body.setAttribute("class", document.body.className + " bar");
// the token list does contain bar
console.log("contains bar? %s", tokenList.contains("bar"))
So, yeah, it might be interesting to have that, but that’s pretty trivial to implement with just one or two lines if you have this because all you would have to do is create an element and ask for an attribute as a token list.
Good point. By haven’t live collections proven they are actually almost useless in practice?
To deal with items (e. g. looping), live collections are almost always converted to static Array, while there is nothing preventing us from having a static token list that would still be able to add()/remove()/etc. its tokens.
Absolutely no. It would just be nice to have a generic way (as long as we are going to make token lists more generic anyway) to convert a string to token list regardless whether the string is an element-attribute value or just a standalone literal (without creating a dummy element). Both ways could coexist.
var a = element.classList; // Predefined token list based on class attribute.
var b = element.tokenListFor('data-foo'); // Token list based on arbitrary attribute.
var c = document.createTokenList('foo bar'); // Also token list, but based on string.
var d = 'foo bar'.toTokenList(); // Possible alternate syntax.
var e = DOMTokenList.from('foo bar'); // Possible Array.from()-like syntax. Eureka!