skip to Main Content

I’m trying to develop a syntax highlighting web component and it will take content placed inside it and syntax highlight it. So something like this:

<fs-highlight data-line-numbers="true" data-language="html">
   any content here ....
</fs-highlight>

This is a prototype implementation and it gets and highlights the content within the element like this:

this._code = hljs.highlight(this.innerHTML.replace(/^s+/g, ''), {
        language: this.language,
      }).value;

And I’m wondering whether it’s correct / fine to use this.innerHTML to grab the content?

The implementation is not using a slot, so the content is not rendered within the element.

However in this demo, vite fails to compile the element. However I’m wondering if that’s just due to how the Stackblitz vite compilation works …(I put a non trivial amount of markup within the element to test it out…)?

Perhaps with local compilation and publishing this goes away … Thoughts?

2

Answers


  1. You have two problems:

    1. Style is not working

    ❌ Problem: That is happening because you style is outside of your webcomponent!

    ✅ Solution: To fix it is just to put the style of @highlight.js inside your component!

    1. Error from vite at console

    ❌ Problem: Actually it is not a problem but an expected behaviour of vite!

    ✅ Solution: There are two possible solutions.

    One is to scape the script tag on html:

    ...
    
    <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@1,800&display=swap" rel="stylesheet" />
    &lt;script type="module" src="./my-timer.js"&gt;&lt;/script&gt;
    <style> ... </style>
    
    ...
    

    So by this way vite will skip the script render but you need to replace by the correct character.

    connectedCallback() {
      super.connectedCallback();
      const code = this.innerHTML
        .replace(/^s+/g, '')
        .replace(/&gt;/g, '>')
        .replace(/&lt;/g, '<');
      this._code = hljs.highlightAuto(
        code, 
        this.language 
          ? { language: this.language } 
          : undefined
      ).value;
    }
    render() {
      const code = this.language 
        ? html`<code class="language-${this.language}">${unsafeHTML(this._code)}</code>`
        : html`<code>(${unsafeHTML(this._code)})</code>`;
      return html`
        <link rel="stylesheet" href="https://unpkg.com/@highlightjs/[email protected]/styles/default.min.css" />
        <h1>Hello</h1>
        <pre>${code}</pre>
      `;
    }
    

    And another solution is to exclude this file from build at vite.config.js.

    Some helpful links:

    Login or Signup to reply.
  2. When you do

    this._code = hljs.highlight(this.innerHTML.replace(/^s+/g, ''), {
            language: this.language,
          }).value;
    

    that async loaded innerHTML might not be there yet. That is why Tools like Lit, Stencil, Shoelace and the 60+ add methods like parsedCallback or even just force shadowDOM on my.

    All you need is to wait for that innerHTML in lighjtDOM to be parsed;
    long explanation: https://dev.to/dannyengelman/web-component-developers-do-not-connect-with-the-connectedcallback-yet-4jo7/edit

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search