microsoft / fluentui-blazor

Microsoft Fluent UI Blazor components library. For use with ASP.NET Core Blazor applications
https://www.fluentui-blazor.net
MIT License
3.79k stars 363 forks source link

fix: FluentBadge content alignment when component is static #1749

Closed swegele closed 6 months ago

swegele commented 6 months ago

Love the controls!!

🐛 Bug Report

Counter page FluentBadge alignment is skewed when page is rendered statically

SERVER and WASM INTERACTIVE: GoodLabel with ServerInteractive

STATIC: BadLabel with ServerInteractive

💻 Repro or Code Sample

  1. Create Project "Auto" - mode declared on each page
  2. Create a copy of Counter.razor and call it CounterStatic.razor.
  3. Change route to "\counter_static"
  4. At top of page delete /@rendermode line to make it static
  5. Add to NavMenu
  6. Run and navigate

🤔 Expected Behavior

All 3 render modes should look the same

😯 Current Behavior

Static is different Upon inspecting elements, it looks like the "0" div ends up outside the badge container.

🔦 Context

Latest version of controls/nuget

oneolddev commented 6 months ago

InteractiveAuto rendermode

image

no rendermode specified

image

vnbaaij commented 6 months ago

So the div that contains the content is not placed in the shadow DOM in SSR mode. I don't think that's really strange but also don't know yet why that is the case.

@swegele 's assumption that all 3 render modes should look the same is a nice one but not necessariy true in practice. We have not claimed anywhere that all components work in SSR mode.

swegele commented 6 months ago

I actually thought about if the different behavior here was logical due to lack of interactivity (example: obviously the button doesn't do anything but that is expected). Couldn't think of a reason why it would render differently....so just passing it on. 😃

Thanks again for your work on this. I'm adopting it in upcoming projects.

swegele commented 6 months ago

@vnbaaij I just noticed something that maybe gives a hint. I deleted cache and loaded a counter page set for: @rendermode InteractiveWebAssembly - thus it had a delay while loading the WASM (few seconds). While it was loading the div with "0" was underneath like in the screenshots in previous comments. But when the WASM loaded then the "0" value popped up where it was supposed to be.

So it does look like the "div" tag literally gets moved inside the badge component during subsequent rendering.

oneolddev commented 6 months ago

It looks like the issue is in the underlying fluent-badge web component. Working on the repro now.

oneolddev commented 6 months ago

@swegele

@vnbaaij I just noticed something that maybe gives a hint. I deleted cache and loaded a counter page set for: @rendermode InteractiveWebAssembly - thus it had a delay while loading the WASM (few seconds). While it was loading the div with "0" was underneath like in the screenshots in previous comments. But when the WASM loaded then the "0" value popped up where it was supposed to be.

So it does look like the "div" tag literally gets moved inside the badge component during subsequent rendering.

The flicker you are seeing is the transition from the initial static rendering generated by the server to the rendering generated by Blazor. All the interactive modes of Blazor Web Apps initially do a static render. This issue makes it more visually apparent.

swegele commented 6 months ago

The flicker you are seeing is the transition from the initial static rendering generated by the server to the rendering generated by Blazor. All the interactive modes of Blazor Web Apps initially do a static render. This issue makes it more visually apparent.

I downloaded the source and took a gander. I was unable to determine why it would ever render content outside the tag.

_P.S. I also realized how there are some very smart people out there! This is very well organized code with tests and auto-documenting etc. A little above my head too!

oneolddev commented 6 months ago

It appears the underlying issue is in the fluent-badge web component. If the fluent-badge component is enclosed in a p tag, this issue appears. The issue doesn't appear when enclosde in a div tag.

Repro

Code

@page "/staticcounter"
@* @rendermode InteractiveAuto *@

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: <FluentBadge Appearance="Appearance.Neutral">@currentCount</FluentBadge></p>

<FluentButton Appearance="Appearance.Accent" @onclick="IncrementCount">Click me</FluentButton>

<hr />

<h2>Repro</h2>

<p>Explicitly using fluent-badge</p>

<h3>Original</h3>
<p>
    Test #1:
    <fluent-badge>
        <div>@currentCount</div>
    </fluent-badge>
</p>

<h3>Workaround</h3>
<div>
    Test #2:
    <fluent-badge>
        <div>@currentCount</div>
    </fluent-badge>
</div>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

Results

image

As to why this doesn't appear when not statically rendered, I suspect it has something to do with the way Blazor DOM is created. I'm guessing the leaf nodes are created first.

@vnbaaij Is this a fluent-badge bug?

oneolddev commented 6 months ago

The workaround would be replacing

<p role="status">Current count: <FluentBadge Appearance="Appearance.Neutral">@currentCount</FluentBadge></p>

with

<div role="status" style="padding-bottom: 1em;">
    Current count: <FluentBadge Appearance="Appearance.Neutral">@currentCount</FluentBadge>
</div>
vnbaaij commented 6 months ago

Great find Gary!

I'm not sue if this is really a web component bug.

Looking at the source at https://github.com/microsoft/fast/tree/archives/fast-element-1/packages/web-components/fast-foundation/src/badge, I can only conclude that this is about the simplest webcomponent of all of them. And besides, the web component has no influence on what it is surrounded with so I'm more inclined to think it is actually a Blazor thing.

vnbaaij commented 6 months ago

I've implemented the replacing of the p with a div in the template code. Will be in next release.

As we have a workaround with that, I'm closing this one for now.

swegele commented 6 months ago

thanks to you both!

oneolddev commented 6 months ago

@vnbaaij

I was able to recreate the issue outside of Blazor in Codepen.

image

vnbaaij commented 6 months ago

Will you create an issue for it in the Fluent UI repo?

oneolddev commented 6 months ago

@vnbaaij

Given that I filed this as an issue in the fluentui repo, can we re-open this and add labels area:fluent-ui-web-components and status:blocked?

vnbaaij commented 6 months ago

Update on this one...I spoke with the Fluent team and it looks like the cause of this is using a div (which is a block element) into an inline element. An easy workaround is to use a span element inside the FluentBadge or, even better, don't wrap the text at all. So approach to solve is:

  1. Don't wrap it, just pass the text...you don't need that div. Updated to illustrate that.
  2. Use an inline element like span
  3. Style the div to be an inline element

You can verify this works by altering the codepen link provided earlier. Also add appearance="accent" to the fluent-badge tags to make them better visible: image

I'm changing the FluentBadge to use a span for wrapping the childcontent

Closing this as a good workaround is now available.

MaRRiK74 commented 5 months ago

@vnbaaij

When using HorizontalPosition and/or VerticalPosition it still has an issue

<FluentCounterBadge Count="counter" Appearance="Appearance.Lightweight" HorizontalPosition="0" VerticalPosition="0">
    <FluentButton Appearance="Appearance.Accent" OnClick="@Increment">
        <FluentIcon Value="@(new Icons.Regular.Size24.Alert())" Color="@Color.Fill" />
    </FluentButton>
</FluentCounterBadge>

@code {
    int counter = 1;

    public void Increment()
    {
        counter++;
    }
}

Badge