I want to write a snippet of code that will traverse the document.body of a page and report all empty block level DOM nodes. This is a pass for SEO/a11y.
I found this article that will seemingly help:
https://css-tricks.com/snippets/jquery/check-for-empty-elements/
$('*').each(function() {
if ($(this).is(':empty') == "") {
//Do Something
}
});
Question #1: How would I convert .is(':empty')
to vanilla js:
function isEmpty(el) {
// Robust isEmpty logic here
}
document.querySelectorAll('*').filter(el => {
return isEmpty(el);
});
Question #2: Will this logic traverse all children too?
Question #3: Could we make this querySelector for only blocklevel elements?
2
Answers
The DOM version of “empty” is that there are no child nodes, which you can check in various ways, probably the two most common are:
firstChild
will benull
if there are no child nodeslength
ofchildNodes
will be0
if there are no child nodesSo for instance, since
null
is falsy andfilter
works with truthy/falsy values:(Note that
querySelectorAll
returns aNodeList
andNodeList
doesn’t have afilter
method, so I used spread notation there to create an array from theNodeList
[sinceNodeList
s are iterable according to the spec now; but see this answer about ensuring thatNodeList
is iterable in your environment].)querySelectorAll('*')
selects every element in the document, many of which will be inside others also on the list.You can certainly tailor it according to the current specification and the default
display
browsers apply to them by doing a list of tag, such asquerySelectorAll("div, p, h1"/*...*/)
. But that doesn’t tell you what’s a block element on that page, since CSS can change thedisplay
of elements. To get up-to-date information, you’d need to usegetComputedStyle
on each element after selecting it and check thedisplay
of the result.Building a list of all of the elements on a page may not be ideal, you might consider a recursive function instead:
But this partially comes down to what you consider “empty.” jQuery’s
:empty
selector is quite literal: An element is only empty if it doesn’t have any child nodes. But your definition may be more loose — for instance, perhaps you want to consider an element that contains only whitespace (directly or in descendant elements) “empty” for your purposes (in which case:!el.textContent.trim()
). The first link above is to the DOM information on MDN which gives you lots to explore to determine your own “empty” if necessary.You can use
children
which is different fromchildNodes
which can contain any node including text node. If usingchildNodes.length
ondiv
like<div>Some Text here</div>
will be return a non empty array even though there is no child element or html tags