Hi Webflow!
I am currently testing code components, and I really like it so far! I think Webflow has done a great job at implementing this.
However, I am running into the following issue. Please note that I am aware, that what I am about to describe is very advanced and was likely not considered when designing code components. Webflow if you are reading this, you should probably get a developer from the code components team to have a look at this. I want to highlight that I believe this is an issue in Webflow’s source code.
What I am trying to do: Inserting / rendering code components with client-side javascript.
Context: Webflow uses a custom element for rendering code-components into a shadow dom.
The problem: Upon inserting a element (see reproduction steps below), I am running into the error shown in the screenshot attached. It says that the root element was not found.
The cause:
- See the constructor of the custom element (copied directly from Webflow’s source code at “webflow.schunk.cfec223be9662d34.js”):
constructor() {
super(),
this.shadowRoot || this.attachShadow({
mode: "open"
})
}
- The following case is not handled properly: when this.shadowRoot is not present,
this.attachShadow({ mode: "open" })is not sufficient to initialize the code-island’s shadow root. Here’s an article documenting how it should be done: Declarative Shadow DOM | web.dev
Reproduction steps (I hope the code-components.website-files.com/*** build is still available):
- Go to sanavita-ag.webflow.io/tv/design
- Paste the following code into the browser console:
const codeIslandString = `<code-island data-loader="{"tag":"FEDERATION","val":{"clientModuleUrl":"https://code-components.website-files.com/6973d23f4b312fb0f9d6078d%2Fmodule%2Fwf-manifest.json","moduleId":"_6973d23f4b312fb0f9d6078d","submoduleId":"WeatherWidget","exportPath":"default","serverModuleUrl":"_"}}" data-props="{"variant":"horizontal","visibility":true,"days":4,"showMinMaxTemp":true,"weatherDelay":10,"forecastDelay":60,"prod":true}" data-slots="[]" data-hydrate="true" data-webflow-context="{"mode":"publish","interactive":true,"locale":"de-CH"}" data-interactive="true" style="display:contents" data-wf--sanavita-components--weather-widget--style-variant="horizontal"><template shadowrootmode="open"><link rel="stylesheet" type="text/css" href="https://code-components.website-files.com/6973d23f4b312fb0f9d6078d%2Fmodule%2F4000ebd49df38fad663c.css"/><div data-root="true" style="display:contents"></div></template></code-island>`;
document.body.insertAdjacentHTML("afterBegin", codeIslandString);
- Find the inserted code-island (first element inside the body), open the shadow root
- Notice how the element is missing
- Check the following properties of the inserted code-island element and notice how they were not initialized:
- rootElement (should be <div data-root="true style=“display:contents;”>)
- root (should be the react root, can be created via codeIsland.renderer.mount(…))
- props
- slots
- webflowContext
My current fix:
export async function initCodeIsland(island: HTMLElement): Promise<HTMLCodeIslandElement> {
// Prevent re-initialization
if (isCodeIsland(island)) return island;
// Ensure island is an unparsed <code-island> element
if (!isCodeIslandUnparsed(island)) {
throw new TypeError(`Parameter island has to be of type HTMLCodeIslandElement.`);
}
// Wait for the constructor of <code-island> to be called
await awaitCodeIslandUpgrade(island as HTMLCodeIslandElement);
// Ensure the <code-island> construction was successful
if (!isCodeIsland(island)) {
throw new Error(`Something went wrong initializing the code-island.`);
}
// Here comes the actual fix
const newRootElement = document.createElement("div");
newRootElement.setAttribute("data-root", "true");
newRootElement.style.display = "contents";
island.shadowRoot.appendChild(newRootElement);
island.rootElement = newRootElement;
let newInternalRoot = island.renderer.mount(newRootElement);
island.root = newInternalRoot;
const dataset = island.parseDataset();
island.props = dataset.props;
island.slots = dataset.slots;
island.webflowContext = dataset.webflowContext;
return island;
}
See the missing helpers of this fix here: github.com/peakpointch/peakflow/blob/main/src/webflow/code-components.ts
All the best!
Lukas
