I have had similar issues with rich text editors and contenteditable
- due to how templates update the DOM you don't want that to be part of a template.
You do this by adding a new element with the non-Lit DOM and then adding that to the DOM that Lit does manage:
class TrumbowygEditor
extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
const div = document.createElement('div');
shadow.appendChild(div);
const style = document.createElement('style');
// Add CSS required
shadow.appendChild(style);
$(div).trumbowyg(); //init
}
}
customElements.define('trumbowyg-editor', TrumbowygEditor);
As this is running in a custom element's shadow DOM Lit won't touch it, you can do:
html`
<div>Lit managed DOM</div>
<trumbowyg-editor></trumbowyg-editor>`;
However, you will have to implement properties and events on TrumbowygEditor
to add everything you want to pass to or get from the nested jQuery component.
You can add the scripts with import
if you can get module versions of jQuery/Trumbowyg (or your build tools support it) or you can add <script>
tags to your component, add fallback loading DOM content in the constructor
, and then on the load event of the <script>
call the $(div).trumbowyg()
to init the component.
While messier and more work I'd recommend the latter as both components are large and (thanks to jQuery being built on assumptions that are now 15 years old) need to load synchronously (<script async
or <script defer
don't work). Especially on slower connections Lit will be ready long before jQuery/Trumbowyg have loaded in, so you want <trumbowyg-editor>
to look good (show spinner, layout in the right amount of space etc) while that's happening.