Can we render a Blazor component as an independent DOM fragment, or somehow else consume it as a standard Web Component within a vanilla HTML/JS page?
This might be a naive question from the Blazor architectural standpoints. I am not a Blazor expert by far, but I think it can be a useful technique for incremental "brownfield" modernization of legacy web applications. I'm surprised this doesn't appear to be officially supported.
To illustrate, consider this simple web component example, which renders a custom element <date-info>
:
// define a custom web component
customElements.define("date-info", class DateInfo extends HTMLElement {
constructor() {
super();
// create an "open" (vs "closed") shadow DOM,
// i.e., accessible to the outside JavaScript
this.attachShadow({ mode: "open" });
}
async connectedCallback() {
console.log(`${this.constructor.name}.${this.connectedCallback.name} called`);
// get the content from the server,
// this could be a Blazor component markup
try {
const response = await fetch("https://worldtimeapi.org/api/ip");
const data = await response.json();
const content = new Date(data.utc_datetime).toString();
this.shadowRoot.innerHTML = `<span>${content}</span>`;
}
catch(e) {
console.error(e);
const info = document.createTextNode(e.message);
this.shadowRoot.appendChild(info);
}
}
});
<!-- use the web component -->
<p>Current time: <date-info/></p>
Now, instead of fetching https://worldtimeapi.org/api/ip
, I'd like to fetch and render a detached markup for a Blazor/Server component, e.g.:
@* this is a Blazor component *@
<p>@(DateTime.Now)</p>
Moreover, I'd expect this markup to remain functional and dynamic, i.e., the client-side DOM events and the server-side updates for this Blazor component to further propagate both ways, through the life cycle of the wrapping web component.
It's surely possible to make it a Blazor @page
and load it into an iframe
, but I'm rather looking to render it as a part of the outer page's DOM.
So far, I've come across this:
Apparently, that wasn't one of Blazor design goals back in 2018: https://github.com/dotnet/aspnetcore/issues/16033.
Later Steve Sanderson created an (unofficial) library to test Blazor components in isolation, which in theory can be used to get a standalone Blazor component markup: https://stackoverflow.com/a/60457390/1768303.
Is it the best approach to tackle this problem, so far?
MS has addressed this limitation, but the solution requires .Net 6.
This was done by the man himself, Steve Sanderson.
UPDATE 11/8/24: The BlazorCustomElements project was added in .NET 7 (and subsequently deleted from that AspLabs repo). Here is the current microsoft doc for how to configure them in .NET 8.