The goal is to create a W3C web component in React which supports arbitrary DOM nodes as children.
The initial markup in the browser should be like this:
<custom-button>
some <u>styled</u> text here
</custom-button>
I would then:
customElements.define()
to register my React code as the implementation of the custom-button
,<custom-button>
,ReactDOM.render(<CustomButton ...>, shadowRoot);
to populate this shadow rootThe DOM structure in the browser is now:
<custom-button>
#shadow-root
<div class="CustomButton">
<!-- x -->
</div>
some <u>styled</u> text here
</custom-button>
But this is not really the desired results; I need the original content of <custom-button>
to render inside <div class="CustomButton">
now.
I am aware of the React children
prop, but as I understand it, it will only work for children that were also declared inside the React implementation and not with arbitrary DOM nodes that were created on the surrounding web component element.
On the other hand I read that Angular implements a concept they call "transclusion" in which they provide slots
which DOM children web component will be mapped into. Is there anything similar in React?
One quick "workaround" that I could think of in React is to:
ref
of the top-level JSX tag,ref.parentNode
ref
as new parentThis would only cover the initialization though. If, at runtime, some other script tried to append more children to <custom-button>
, or re-order or delete previously inserted children, this would probably fail.
I have just realized that the <slot />
of the web components standard solves the problem.
So, to reflect the content of the <custom-element>
inside the React component, the following is completely sufficient:
render() {
return (
<div className="customElement">
...
<slot />
...
</div>
);
}