Search code examples
c#html.netblazorweb-component

Can we consume a Blazor component as a Web Component within a regular non-Blazor HTML page?


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:


Solution

  • MS has addressed this limitation, but the solution requires .Net 6.

    https://github.com/aspnet/AspLabs/tree/a5137f28510dd3673a28fa1c29e1cf7415ecac2c/src/BlazorCustomElements

    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.