I need to get all DOM elements within DOM element myRootElement
, that satisfy the following conditions:
div
or blockquote
)foo
or bar
)If it were just condition 1, I know I can write:
let elementsWithRightName = myRootElement.querySelectorAll("div, blockquote");
and then I can filter the result, like so:
let isOfNiceClass = (elem) => ["foo", "bar"].includes(elem.className);
let elementsOfInterest = [...elementsWithRightName].filter(isOfNiceClass);
but is there a better/most elegant/idiomatic way to apply both filters?
Use .matches()
:
classNames.some(c => elem.matches(`.${c}`))
Or, with the new-ish :is()
/:where()
:
const tags = ['div', 'blockquote'];
const classes = ['foo', 'bar', 'baz'];
const selector = `:is(${tags.join(', ')}):is(${classes.map(c => '.' + c).join(', ')})`;
// ':is(div, blockquote):is(.foo, .bar, .baz)'
const elementsOfInterest = myRootElement.querySelectorAll(selector);
For more complex cases, it depends. However, I'd say a CSS selector is probably the most efficient way to search for elements: browsers optimize it under the hood so we don't have to. I'm not sure about XPath though.