I'm creating a custom element that will be able to convert its contents from markdown to HTML. However, I'm not able to get the contents of my custom elements.
<!doctype html>
<html>
<body>
<template id="mark-down">
<div class="markdown"></div>
</template>
<!-- Converts markdown to HTML -->
<script src="https://cdn.jsdelivr.net/gh/showdownjs/showdown/dist/showdown.js"></script>
<script>
customElements.define('mark-down',
class extends HTMLElement {
constructor() {
super()
let template = document.querySelector('#mark-down').content
this.attachShadow({ mode: 'open' }).appendChild(template.cloneNode(true))
}
connectedCallback() {
console.log(this) // Returns the whole <mark-down> node and its contents
console.log(this.innerHTML) // So why does this return a blank string?
// This should theoretically work --> let markdown = this.innerHTML
let markdown = '## Test'
let converter = new showdown.Converter()
let html = converter.makeHtml(markdown)
this.shadowRoot.innerHTML = html;
}
});
</script>
<main>
<mark-down>
## Our Markdown
These contents should get converted
* One
* Two
* Three
</mark-down>
</main>
</body>
</html>
My issue is in the connectedCallback()
. When logging this
, I get the whole <mark-down>
node with its contents in markdown. However, it doesn't seem to have valid properties. Using innerHTML
returns a blank, where it should return the markdown; other combinations, like this.querySelector('mark-down')
, return null
.
What can I do to get the contents of my custom element?
I wrote a (very) long Dev.to Blogpost:
Web Component Developers do not connected with the connectedCallback yet
The easiest workaround is a setTimeout
in the connectedCallback
<script>
customElements.define('my-element', class extends HTMLElement {
connectedCallback() {
console.log(this.innerHTML);// "" in all Browsers
setTimeout(() => {
// now runs asap
console.log(this.innerHTML); // "A"
});
}
})
</script>
<my-element>A</my-element>
What this and all mentioned workarounds do is postpone code execution until the DOM is fully parsed.
setTimeout
runs after DOMContentLoaded
, but if you wrap everything in DOMContentLoaded
the whole Element creation runs late, same applies for defer
or placing <script>
at the end of your page
Supersharp explains the why better in:
wait for Element Upgrade in connectedCallback: FireFox and Chromium differences