Below is the Lit Element I’m trying to make to display a codeblock with Prism.js code highlighting. For some reason the slot content is not showing up in the firstUpdated() function when I query the #code element. I can run the same code in the dev tools console and I do see the content so I’m not really sure why it isn’t working in the firstUpdated() function.
The Lit docs mention to use firstUpdated() to access slot content: https://lit.dev/docs/components/shadow-dom/#accessing-nodes-in-the-shadow-dom
Here is the html markup
<tb-code-block language="markup">
<div>slot content</div>
<span>here</span>
</tb-code-block>
import { LitElement, html, css } from "lit";
import { customElement, property } from "lit/decorators.js";
import * as Prism from "prismjs";
import "prismjs/components/prism-r.min.js";
import "prismjs/components/prism-javascript.min.js";
import "prismjs/components/prism-markup.min.js";
type LanguageOption = "r" | "javascript" | "markup";
@customElement("tb-code-block")
export class CodeBlock extends LitElement {
static styles = css`
#hide {
display: none !important;
}
`;
@property({ type: String }) language: LanguageOption = "javascript";
@property({ type: String }) theme: string = "/node_modules/prismjs/themes/prism.css";;
@property({ type: Boolean }) lineNumbers = false;
firstUpdated() {
if (!this.shadowRoot) return;
const code = this.shadowRoot!.querySelector(
"#code",
) as HTMLSlotElement | null;
// console.log('code',code); => slot id="code"></slot>
let nodes = code!
.assignedNodes() as HTMLElement[];
// console.log('nodes',nodes); => []
let codeCombined = "";
for (let index = 0, len = nodes.length; index < len; ++index) {
codeCombined += nodes[index].innerHTML;
}
codeCombined = codeCombined.replace(/^s+|s+$/g, "");
// console.log('codeCombined',codeCombined); => ""
if (this.language && Prism.languages[this.language]) {
const highlight = Prism.highlight(
codeCombined,
Prism.languages[this.language],
this.language,
) as string;
// console.log('highlight',highlight); => ""
const output = this.renderRoot.querySelector(
"#output",
) as HTMLElement | null;
if (output) {
output.innerHTML = highlight;
}
}
}
render() {
return html`
<link rel="stylesheet" href="${this.theme}" />
<pre class="language-${this.language}"><code id="output"></code></pre>
<div id="hide">
<slot id="code"></slot>
</div>
`;
}
}