Skip to content

Instantly share code, notes, and snippets.

@surajp
Created August 15, 2023 17:27
Show Gist options
  • Save surajp/4947343801681ed716472d576b62a97d to your computer and use it in GitHub Desktop.
Save surajp/4947343801681ed716472d576b62a97d to your computer and use it in GitHub Desktop.
Custom Elements in LWC
<template>
<h2>Dynamic Component</h2>
<div lwc:dom="manual" class="container"></div>
</template>
import { LightningElement } from "lwc";
//eslint-disable-next-line no-unused-vars
import PopUpInfo from "./popupInfo.js"; //this could probably also be a static resource
import logo from "@salesforce/resourceUrl/logo";
export default class DynaComp extends LightningElement {
_isRendered = false;
logoUrl = logo;
_createComp() {
const popupInfo = document.createElement("popup-info");
popupInfo.setAttribute("data-text", "This is a dynamic component");
popupInfo.setAttribute("img", this.logoUrl);
this.template.querySelector(".container").appendChild(popupInfo);
}
renderedCallback() {
if (!this._isRendered) {
this._isRendered = true;
this._createComp();
}
}
}

Add an image static resource named logo

// Create a class for the element
// Source: https://github.com/mdn/web-components-examples/blob/main/popup-info-box-web-component/main.js
class PopUpInfo extends HTMLElement {
shadow; /** using this to store a reference to the shadowroot since this.shadowRoot
//does not seeem to be available when we use "mode: closed" in the attachShadow call
//lwc does not support "mode": "open" in the attachShadow call. not sure if this is the right way **/
connectedCallback() {
const text = this.getAttribute("data-text");
const imgUrl = this.getAttribute("img");
if (text) {
this.shadow.querySelector(".info").textContent = text;
}
if (imgUrl) {
this.shadow.querySelector("img").src = imgUrl;
}
}
constructor() {
// Always call super first in constructor
super();
// Create a shadow root
const shadow = this.attachShadow({ mode: "closed" });
this.shadow = shadow;
// Create spans
const wrapper = document.createElement("span");
wrapper.setAttribute("class", "wrapper");
const icon = document.createElement("span");
icon.setAttribute("class", "icon");
icon.setAttribute("tabindex", 0);
const info = document.createElement("span");
info.setAttribute("class", "info");
// Take attribute content and put it inside the info span
const text = this.getAttribute("data-text");
info.textContent = text;
// Insert icon
let imgUrl;
if (this.hasAttribute("img")) {
imgUrl = this.getAttribute("img");
} else {
imgUrl = "img/default.png";
}
const img = document.createElement("img");
img.src = imgUrl;
icon.appendChild(img);
// Create some CSS to apply to the shadow dom
const style = document.createElement("style");
console.log(style.isConnected);
style.textContent = `
.wrapper {
position: relative;
}
.info {
font-size: 0.8rem;
width: 200px;
display: inline-block;
border: 1px solid black;
padding: 10px;
background: white;
border-radius: 10px;
opacity: 0;
transition: 0.6s all;
position: absolute;
bottom: 20px;
left: 10px;
z-index: 3;
}
img {
width: 1.2rem;
}
.icon:hover + .info, .icon:focus + .info {
opacity: 1;
}
`;
// Attach the created elements to the shadow dom
shadow.appendChild(style);
console.log(style.isConnected);
shadow.appendChild(wrapper);
wrapper.appendChild(icon);
wrapper.appendChild(info);
}
}
customElements.define("popup-info", PopUpInfo);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment