dotnet / razor

Compiler and tooling experience for Razor ASP.NET Core apps in Visual Studio, Visual Studio for Mac, and VS Code.
https://asp.net
MIT License
499 stars 191 forks source link

Blazor Allow PascalCased Component Names Matching Reserved HTML Tags #7656

Open xiety opened 4 years ago

xiety commented 4 years ago

Describe the bug

Custom component with name Input works fine until I've added RenderFragment parameter to it and put the component into a @foreach loop.

To Reproduce

Page.razor

@foreach (var column in new string[] { "1", "2" })
{
    <Input>
        <Lookup></Lookup>
    </Input>
}

Input.razor

@code
{
    [Parameter]
    public RenderFragment Lookup { get; set; }
}

Expected behavior

Compile without errors.

Actual behavior

error RZ1026: Encountered end tag "Input" with no matching start tag.  Are your start/end tags properly balanced?

Additional information

Doesn't compile inside @if as well.

Workaround

Rename component from Input to CustomInput

javiercn commented 4 years ago

@xiety thanks for contacting us.

This is by design. You are trying to "override" an HTML element and that's not possible as HTML tags are case-insensitive. If you want to have a component named Input then you need to fully qualify its name.

If you switch that to the following it works as expected. ``

` ``
xiety commented 4 years ago

@javiercn, it seems to me that the error is not very informative. And my original sample works normally if you remove only foreach or if you remove only RenderFragment. If this is by design that it should not work anyway.

rynowak commented 4 years ago

This is by design. You are trying to "override" an HTML element and that's not possible as HTML tags are case-insensitive. If you want to have a component named Input then you need to fully qualify its name.

While this isn't something we'd recommend, it also doesn't make sense that we'd err-out in this case. We should take a look at this.

javiercn commented 4 years ago

@rynowak putting this on your plate as its something likely you can only investigate. If you think @ajaybhargavb or @NTaylorMullen can feel free to pass it on.

NTaylorMullen commented 4 years ago

Oh boy this is an interesting one. Without debugging through it and going purely off of memory what I believe is happening is our initial parse of the Razor document is what's generating this error. When the parse sees a void Input tag (tags are case insensitive) inside of a C# block (we enforce well-formed tags) it treats the tag as "complete. When it then sees the end Input tag it has already completed previous Input so it handles the end tag as a malformed unmatched endtag. Later on when we apply Components to the Razor parse tree we then allow the non-void behavior for Input; however, it's too late. An error was already logged from the first parsing phase which we don't end up removing (we don't ever remove errors from the original phase) and it ends up flowing to the end-user.

mkArtakMSFT commented 4 years ago

Given the complexity involved we will be able to achieve this if we enforce "Pascal-casing means Razor component" approach.

davidmilligan commented 3 years ago

encountering a very similar issue when you name a blazor component 'Text'. It works fine most of the time, but there will be random situations where you have to fully qualify the name (e.g. directly inside ifs or foreachs) because it thinks you're trying to use <text> instead of <Text>

TanayParikh commented 3 years ago

Seems like this is an issue with using the Pascal cased names of reserved tag names, in very specific contexts. While this should work in theory, it does have the very simple workaround of not using the reserved names (ie. if a lowercase tag is reserved, consider the Pascal cased tag as reserved as well).

I'm going to leave this open for future tracking, however this'll probably be pretty low on our backlog.

NTaylorMullen commented 3 years ago

While this should work in theory, it does have the very simple workaround of not using the reserved names (ie. if a lowercase tag is reserved, consider the Pascal cased tag as reserved as well).

IIRC I've seen several people use these types of tags indirectly by consuming packages from component vendors 😢