I'm pulling my hair out on this one. I have a JavaScript class that clones a <template> element and then is appended to the document body. I want to then manipulate that newly created element... but it always insists it's undefined.
Template
<template id="js-modalTemplate">
<aside class="o--modal" style="display: none">
<button class="o-modal__close-button">
Close
</button>
<div><iframe class="js-video" src=""></iframe></div>
</aside>
</template>
ES Module
export default class Modal {
constructor() {
const template = document.getElementById('js-modalTemplate');
const modalTemplate = template.content.cloneNode(true)
this.modalElement = document.body.appendChild(modalTemplate)
console.log(this.modalElement)
this.modalElement.style.display = "block"
}
}
Script element
<script type="module">
import VideoModal from "{{ Vite::asset('resources/js/components/Modal.js') }}"
window.testModal = new Modal()
</script>
The console.log output of the element sometimes appears in full, but sometimes it's empty (no changes to code)...
Empty fragment:
Fragment with content:
However I always get the following error, no matter what:
Uncaught TypeError: Cannot set properties of undefined (setting 'display')
And the element always appears in the DOM at the expected place.
Things I've tried
- Moving the script element to the bottom of
document.bodyand addingdefer. (Neither of these things should be necessary because it's an ES Module anyway and so it automatically deferred.) - Placing the code within
window.onloadfor similar reasons
There's just something about using a <template> that causes this issue, but I've never used them before so I don't know what!


You could get the top level element (the
<aside>) from the fragment throughfirstElementChildbefore appending it to the DOM.