Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does setting element.className = null result in class="null"?

Apparently, attempting to set the className property to null doesn't erase the class attribute — instead, it replaces it with a class name that's literally called "null":

document.querySelector('p:nth-of-type(2)').className = null;
p[class]::before {
  content: '<p class="' attr(class) '">';
}

p:not([class])::before, p[class=""]::before {
  content: '<p>';
}

p.null {
  color: red;
}
<p class="a b c">
<p class="x y z">

On top of that, there is full interop.

I would have expected className = null to erase the class attribute, or that null would convert to an empty string for the purposes of className, or at the very least that it would produce a TypeError.

What gives?

like image 345
BoltClock Avatar asked Oct 27 '25 10:10

BoltClock


1 Answers

In JavaScript, null does not convert to an empty string. It converts to the string "null". You can see this if you convert it manually:

var x = String(null);
console.log(x);

This is also mentioned in MDN's documentation of DOMString:

Passing null to a method or parameter accepting a DOMString typically stringifies to "null".

The className property (and related properties like id) are of type DOMString, which maps directly to String in JS. It's this conversion that results in a class name literally called "null", which is then reflected in the class attribute and matched by such selectors as .null and [class~=null].

If you were expecting null to convert to an empty string because both are falsy values, it doesn't work that way. Just because two values are falsy, i.e. both values result in false when converted to Boolean, does not make those two values equal to one another, not even loosely. In particular, most objects, including strings, are never loosely equal to null, since something cannot be equal to nothing (with a few exceptions for legacy reasons). There is a handy comparison table here in MDN that you can refer to.

To erase the class attribute and remove all class names from an element, set className to the empty string instead of null:

document.querySelector('p:nth-of-type(2)').className = '';
p[class]::before {
  content: '<p class="' attr(class) '">';
}

p:not([class])::before, p[class=""]::before {
  content: '<p>';
}

p.null {
  color: red;
}
<p class="a b c">
<p class="x y z">

(You can also iterate classList and remove each class individually, if browser compatibility is not a concern for you. Interestingly, for the performance junkies, modifying classList is actually faster than setting className — see the comment below. Presumably, setting className has the side effect of also updating classList, which could be the reason why it's slower.)

like image 103
BoltClock Avatar answered Oct 29 '25 00:10

BoltClock



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!