matthewp / haunted

React's Hooks API implemented for web components 👻
BSD 2-Clause "Simplified" License
2.58k stars 92 forks source link

Haunted not clearing innerHTML before first render #444

Open micahjon opened 1 year ago

micahjon commented 1 year ago

I'm working on upgrading BeFunky to the latest version of Lit and Haunted.

We currently don't use shadow DOM for components, and I noticed that when useShadowDOM: false is set, Haunted doesn't clear the initial content in the custom element before rendering. Initial content is really helpful for progressive enhancement, avoiding layout shift when the component JS loads and renders, e.g.

<custom-element>
  <span class="loading-placeholder">Loading...<span>
</custom-element>

This was fine in Lit 1.*, but in Lit 2.*, the render() function doesn't clear the container's contents.

From the Lit upgrade guide: https://lit.dev/docs/releases/upgrade/#lit-html

render() no longer clears the container it's rendered to on first render. It now appends to the container by default.

I'm guessing we'll need to set component.innerHTML = '' before the first render manually when useShadowDOM: false is set.


Bug replicated in Codepen: https://codepen.io/pranksinatra/pen/XWqrpBj

micahjon commented 1 year ago

Submitted a PR that should fix this issue. Open to any and all feedback, thanks!

tommywalkie commented 1 year ago

Slightly related to the question, is there a pragmatic way to use slotted content and/or retrieve the initial content before the first render? Currently playing with this on haunted@5.0.0:

function SampleCard(element: HTMLElement) {
  const [slot] = useState(Array.from(element.childNodes));
  element.innerHTML = "";
  return html`<div class="whatever-container">${slot}</div>`; 
}

Probably won't work after https://github.com/matthewp/haunted/pull/445 is merged.