This PR allows passing children for elements even with shadow: false. It only works for first render, if the children are modified after first render (i.e. if the element is used in a framework such as LitElement), children are not updated.
It also cleans up the overall usage with shadow: false by getting rid of the <slot> wrapper element, attaching the context event listener on the custom element itself.
Why is this PR needed
It partly fixes #41.
Children are a big part of a component design, not being able to pass children is a strong limitation. As of now, passing children results in them being duplicated. With this PR, at least the initial rendering is correct. It also enables internally handled children to be hydrated when using SSR.
Taking the following example:
function MyComponent({ children }) {
return (
<div class="children-go-here">
{children}
</div>
)
}
register(MyComponent, 'my-component', [], { shadow: false })
This PR touches at various points of the wrapper's lifecycle. The first breaking change here is the addition of the following in toVdom:
// Remove all children from the topmost node in non-shadow mode
if (!shadow && nodeName) {
element.innerHTML = '';
}
This snippet removes all children present in the original element before rendering (and after having copied them to the vDom's children), thus removing the duplicated/wrongly placed children.
The PR also removes the manual call to connectedCallback when handling props update before initial render. In place, it stores the props in the _props temporary variable, so that they are applied at first render. This allows to avoid a bug where the component is rendered inside itself when connectedCallback is called multiple time.
The rest is implementation details about removing the <slot> element when not using ShadowDOM, has it is not needed.
Misc
Removing the <slot> wrapper when not using ShadowDOM allows for a cleaner DOM, but it does come at a cost: we loose the ability to unregister the _preact event listener. We could add this ability back by using a useEffect hook in the Slot component, but I did not want to add a dependency on preact/hooks there, since the library seems to avoid it.
The usage is also a bit strange since modifying the children of the custom elements will not update the children of the Component, since it does not call attributeChangedCallback. I've not found a way around this.
Finally, maybe handling children with non ShadowDOM is not something you want to be allowed, in which case this PR can just be closed 🙂
What does this PR do
This PR allows passing children for elements even with
shadow: false
. It only works for first render, if the children are modified after first render (i.e. if the element is used in a framework such as LitElement), children are not updated.It also cleans up the overall usage with
shadow: false
by getting rid of the<slot>
wrapper element, attaching thecontext
event listener on the custom element itself.Why is this PR needed
It partly fixes #41. Children are a big part of a component design, not being able to pass children is a strong limitation. As of now, passing children results in them being duplicated. With this PR, at least the initial rendering is correct. It also enables internally handled children to be hydrated when using SSR.
Taking the following example:
The resulting markup without this PR is:
With this PR, it becomes:
Implementation details
This PR touches at various points of the wrapper's lifecycle. The first breaking change here is the addition of the following in
toVdom
:This snippet removes all children present in the original element before rendering (and after having copied them to the vDom's children), thus removing the duplicated/wrongly placed children.
The PR also removes the manual call to
connectedCallback
when handling props update before initial render. In place, it stores the props in the_props
temporary variable, so that they are applied at first render. This allows to avoid a bug where the component is rendered inside itself whenconnectedCallback
is called multiple time.The rest is implementation details about removing the
<slot>
element when not using ShadowDOM, has it is not needed.Misc
Removing the
<slot>
wrapper when not using ShadowDOM allows for a cleaner DOM, but it does come at a cost: we loose the ability to unregister the_preact
event listener. We could add this ability back by using auseEffect
hook in theSlot
component, but I did not want to add a dependency onpreact/hooks
there, since the library seems to avoid it.The usage is also a bit strange since modifying the children of the custom elements will not update the children of the Component, since it does not call
attributeChangedCallback
. I've not found a way around this.Finally, maybe handling children with non ShadowDOM is not something you want to be allowed, in which case this PR can just be closed 🙂