I just realised that actually you can, and that the first example, m1, actually does replace the documentElement and removes its event listeners. The interesting thing is that there were no event listeners on it in the first place, they were on the document itself not the document element. The developer tools (in FireFox) tricks you and shows them as being attached to the <html>
element, even though they aren’t technically attached to an element. If you modify the example to actually attach the events to the document.documentElement
instead of the document itself the event will be disabled when you click m1:
document.documentElement.addEventListener('contextmenu', function (e) {
alert('still listening');
e.preventDefault();
})
function m1() {
var doc = document.implementation.createHTMLDocument();
document.replaceChild(
document.importNode(doc.documentElement, true),
document.documentElement
);
}
function m2() {
document.close();
document.write('<html></html>');
}
<button onclick="m1()">m1</button>
<button onclick="m2()">m2</button>
Originally I was going to say no, and that you can’t do it, as user Livingston Samuel states in this similar but not identical question: “You cannot replace the current document object or any document object with the Document object created with createHTMLDocument method.”
Sticking to my original question though, it is not the document I was asking about, it was the documentElement. So given the modified code above, I will say that Yes, it is possible.
It is interesting to see that the event listeners are displayed on the html element in FireFox whether they are attached to the document object or the documentElement object, as of version 81. I might expect that they would instead not display them at all when attached to document
, or put them on some abstract object. An iframe does have an abstract object available labeled #document
, but it is not used for this and has no event label:

It is also interesting that document.write()
actually destroys the events on the document
object, not just the document.documentElement
. It might be documented somewhere in here but I can’t seem to find it.
After testing Chrome I noticed that the developer tools distinguishes between events being attached to the documentElement:

and the document itself:

I’m not sure what’s behind this question but I may guess, that you are having issues when the objects and events are re-created in the page.
If this is the case, as can be seen in MDN (https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild), despite you remove the elements on the HTML, they still could remain in the memory for a while, waiting for the garbage collector to clean them up.
So in case you wish to remove safely a piece of code that contains events, the safest way is to remove the events first using your favorite library (like jQuery) or using the DOM through native JavaScript:
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
Once you have removed all events, the you could remove all elements, and the safest way to do this (from a memory point of view) is through a loop, removing the inner elements first and the parent elements then, and so on.
You can use document.getElementById('id-here').innerHTML = ""
, like so:
<html id="the-website">
<body>
<input type="button" onclick="document.getElementById('the-website').innerHTML = '';" value="Don't click me plz!">
</body>
</html>
In the example below:
- If you right click the document, it will tell you it’s listening.
- If you click m1 it will replace the document element, but right clicking the document will still inform you that it’s listening. You must right click near the top because the document has no contents.
- If you click m2 it will overwrite the document contents and right clicking near the top no-longer does anything. Examining the document in the development tools verifies that the event handlers are gone.
- After pressing one button, you must “run code snippet” again to try the next because this demonstration is destructive.
With this information. Is there a different way to destroy the document and replace it with a new one, in such a way that the event handlers are destroyed, without using the document.write()
function?
document.write()
is prone to errors and its usage is “strongly discouraged”, but I would still like to be able to destroy the document and it’s event listeners.
document.addEventListener('contextmenu', function (e) {
alert('still listening');
e.preventDefault();
})
function m1() {
var doc = document.implementation.createHTMLDocument();
document.replaceChild(
document.importNode(doc.documentElement, true),
document.documentElement
);
}
function m2() {
document.close();
document.write('<html></html>');
}
<button onclick="m1()">m1</button>
<button onclick="m2()">m2</button>
To be clear, button/function “m1” fails my goals, because although the document element was replaced, the event handlers from the previous document element were preserved for some reason. I would like to achieve what m2 achieves, but without using document.write
and document.close
which are recommended against.
Addendum:
This question is strictly for the sake of better understanding the limits of the language and the engines that implement them. Please do not try to read between the lines or solve some alternate goal. It’s just a question of whether something is possible or not.
I don’t need to know how to remove event listeners or manage event listeners, or remove all child elements of a document. I would like to know if it’s possible to destroy the document element itself, leaving no <html>
tag whatsoever and leaving none of its event listeners behind. This is possible with document.write()
but I simply want to know if there are alternate means of achieving this exact goal, not any other assumed goals.
Another thing to keep in mind – listeners can be added even higher than the document, to the