dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.48k stars 10.04k forks source link

Support for Blazor Custom elements to handle nesting of components. #45421

Open DanielCordell opened 1 year ago

DanielCordell commented 1 year ago

Is there an existing issue for this?

There's this issue https://github.com/dotnet/aspnetcore/issues/38369 but it refers to angular specifically, but I'm focusing on a pure HTML context & trying to consider more blazor functionality (arbitrarily named RenderFragments, Cascading Parameters). If it's a duplicate my apologies.

Is your feature request related to a problem? Please describe the problem.

I built a very simple test-bench for custom elements, with the idea that I could use them in place of building some code in razor. The feature isn't very extensively documented so I wanted to see if I could find some limitations. I notice that I can't nest components inside each-other, even if the outer component has a RenderFragment ChildContent parameter.

If I have the HTML:

<data-grid>
    <data-column name="Col1" />
    <data-column name="Col2" />
    <data-column name="Col3" />
</data-grid>

(where data-grid is a Custom Element defined in Blazor, with a RenderFragment ChildContent parameter, and data-column is another component that simply renders the text passed into the name attribute.)

It does initially render as such if I put a DOM breakpoint in, but then after the blazor lifecycle has run, all of the data-column elements get removed from the DOM (and therefore the blazor components get destroyed). What you're left with is the actual output of rendering the DataGrid razor component. It would be nice if there was such a way of having nested components work as expected (possibly with Shadow DOM & slots for other render fragments).

Describe the solution you'd like

Ideally, nesting elements with renderfragments in Blazor should be able to be replicated in HTML with custom elements. Possibly having each renderfragment create a 'slot' in the shadow dom?

Would also be very cool if cascading parameters (not type parameters) worked this way as well, although I suspect that's a much harder problem, and likely not feasible.

Additional context

I built a really hacked-together demo of a PoC of simple nesting, by declaring my own window.registerCustomBlazorElement function. https://github.com/DanielCordell/CustomElementsDemo/blob/main/wwwroot/index.html#L34

However it's definitely not the way to go about doing this, as it basically uses the fact that on element creation blazor hasn't overwritten the DOM yet to shove the child nodes of the element into the shadow DOM.

ghost commented 1 year ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

veikkoeeva commented 1 year ago

If I may add that in addition to slots, styling with Constructable Stylesheets or something similar could be useful. That is, scoping styles to components and then reusing them. Without hacking things together like has been now in this issue to demonstrate the case. Since there is a scoping system in Blazor, I'll add https://css-tricks.com/styling-a-web-component/.

Or in genenral https://www.dannymoerkerke.com/blog/everything-you-always-wanted-to-know-about-web-components-but-were-afraid-to-ask/ just in case. Tangentially related, server-side rendering of custom elements with dynamic client side elements as exemplified in the post could be interesting with this slotting and Blazor or being more reactive.

veikkoeeva commented 1 year ago

@DanielCordell Besides your hack (or maybe of interest more to general readership), one way of going could perhaps be like in Danny's blog post (oruse something like Lit, but both Lit and Blazor track some things with comment nodes, so won't mix well I linked easlier), and then P/Invoke to WASM modules as that's possible now in .NET 7. Even with this one probably would like a bit support from Razor engne, especially concerning Constructable Stylesheets (and running a preprocessor on the CSS files).

DanielCordell commented 1 year ago

These are really interesting articles! It bypasses part of my hack but I'd still need to handle cascading parameters with JS in some way.

veikkoeeva commented 1 year ago

@DanielCordell Many problems here.

Insprired by you, I tried to create s simple wizard having simple child (HTML tables, or grids in you case) custom element -- using Blazor Custom Elements. This seem to work, they render and stepping back and forth works. However, if I add a next step button to the parent wizard and try to make the next step conditional on row selected in the child component, I seem to struggle with how to pass that information back to parent.

I see from https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 some of this does not work until .NET 7.0.1, but I am not sure if there's in fact something more with custom elements that will not be covered with new versions either. Maybe one way is to simply just use message bus.

dotnet-policy-service[bot] commented 9 months ago

Looks like this PR hasn't been active for some time and the codebase could have been changed in the meantime. To make sure no conflicting changes have occurred, please rerun validation before merging. You can do this by leaving an /azp run comment here (requires commit rights), or by simply closing and reopening.

dotnet-policy-service[bot] commented 9 months ago

Looks like this PR hasn't been active for some time and the codebase could have been changed in the meantime. To make sure no conflicting changes have occurred, please rerun validation before merging. You can do this by leaving an /azp run comment here (requires commit rights), or by simply closing and reopening.

DanielCordell commented 9 months ago

@wtgodbe could you please remove the label again?