JSFiddle - React, Tailwind, and code Playground
HTML
<!-- Assume you use some crappy browser without support of querySelector or querySelectorAll. The browser does however support:
children, childNodes, className, getElementById, getElementsByClassName, getElementsByTagName, parentNode, parentElement, tagName, id, getAttribute
Implement polyfill for querySelector and querySelectorAll that supports:
class selectors
tag selectors
id selectors
descendant selectors
Examples of selectors that need to be supported:
.some-class
.some-class.special
div.some-class
div
div.some-class span
#my-id
#my-id .some-class
#my-id.some-state .some-class
-->
<div id="root" class="a">
<div class="b">
<div class="a i j">
<span class="d k"></span>
</div>
<div class="c">
<div class="a">
<div class="d"></div>
</div>
</div>
</div>
</div>
CSS
#root {
height: 200px;
width: 200px;
border: 1px solid red;
}
JavaScript
function querySelector(selector, nodes, recur) {
var reId = /^#[\w-_]+/i;
var reClass = /^\.[\w-_]+/i;
var reTag = /^[\w-_]+/i;
var nextNodes = [];
var res;
var curSelector, query, filter;
if (!nodes || !nodes.length) {
return null;
}
if (!selector) {
return nodes[0];
}
if (recur && selector[0] !== ' ') {
if (reId.test(selector)) {
curSelector = reId.exec(selector)[0];
filter = filterID;
}
if (reClass.test(selector)) {
curSelector = reClass.exec(selector)[0];
filter = filterClass;
}
for (var j=0; j<nodes.length; j++) {
if (filter(curSelector, nodes[j])) {
nextNodes.push(nodes[j]);
}
}
return querySelector(selector.substr(curSelector.length), nextNodes, true);
} else {
selector = selector.trim();
}
if (reId.test(selector)) {
curSelector = reId.exec(selector)[0];
query = queryID;
}
if (reClass.test(selector)) {
curSelector = reClass.exec(selector)[0];
query = queryClass;
}
if (reTag.test(selector)) {
curSelector = reTag.exec(selector)[0];
query = queryTag;
}
for (var i=0; i<nodes.length; i++) {
nextNodes = query(curSelector, nodes[i]);
res = querySelector(selector.substr(curSelector.length), nextNodes, true);
if (res) {
return res;
}
}
return null;
}
function queryID(selector, node) {
var n = node.getElementById(selector.substr(1));
if (n) return [n];
return [];
}
function queryClass(selector, node) {
return node.getElementsByClassName(selector.substr(1));
}
function queryTag(selector, node) {
return node.getElementsByTagName(selector);
}
function filterID(selector, node) {
return node.id === selector.substr(1);
}
function filterClass(selector, node) {
var cls = ' ' + node.className + ' ';
return cls.indexOf(' ' + selector.substr(1) + ' ') > -1;
}
function querySelectorAll(selector, nodes, recur) {
if (!selector) {
return nodes;
}
if (!nodes || !nodes.length) {
...