Skip to content

Commit 768425e

Browse files
committed
Additional loading indicator scenarios
1 parent 03b2c9f commit 768425e

File tree

1 file changed

+153
-53
lines changed

1 file changed

+153
-53
lines changed

aspnetcore/blazor/fundamentals/startup.md

Lines changed: 153 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -572,77 +572,43 @@ A loading progress indicator shows the loading progress of the app to users, ind
572572

573573
:::moniker range=">= aspnetcore-8.0"
574574

575-
### Blazor Web App loading progress
575+
### Blazor Web App loading indicator
576576

577-
The loading progress indicator used in Blazor WebAssembly apps isn't present in an app created from the Blazor Web App project template. Usually, a loading progress indicator isn't desirable for interactive WebAssembly components because Blazor Web Apps prerender client-side components on the server for fast initial load times. For mixed-render-mode situations, the framework or developer code must also be careful to avoid the following problems:
577+
The loading indicator used in Blazor WebAssembly apps isn't present in an app created from the Blazor Web App project template. Usually, a loading indicator isn't desirable for interactive WebAssembly components because Blazor Web Apps prerender client-side components on the server for fast initial load times. For mixed-render-mode situations, the framework or developer code must also be careful to avoid the following problems:
578578

579579
* Showing multiple loading indicators on the same rendered page.
580580
* Inadvertently discarding prerendered content while the .NET WebAssembly runtime is loading.
581581

582582
<!-- UPDATE 10.0 Will be removed for a new feature in this area.
583583
Tracked by: https://github.com/dotnet/aspnetcore/issues/49056 -->
584584

585-
A future release of .NET might provide a framework-based loading progress indicator. In the meantime, you can add a custom loading progress indicator to a Blazor Web App.
585+
A future release of .NET might provide a framework-based loading indicator. In the meantime, you can add a custom loading indicator to a Blazor Web App.
586586

587-
Create a `LoadingProgress` component in the `.Client` app that calls <xref:System.OperatingSystem.IsBrowser%2A?displayProperty=nameWithType>:
587+
#### Per-component Interactive WebAssembly rendering with prerendering
588588

589-
* When `false`, display a loading progress indicator while the Blazor bundle is downloaded and before the Blazor runtime activates on the client.
589+
*This scenario applies to per-component Interactive WebAssembly rendering (`@rendermode InteractiveWebAssembly` applied to individual components).*
590+
591+
Create a `ContentLoading` component in the `Layout` folder of the `.Client` app that calls <xref:System.OperatingSystem.IsBrowser%2A?displayProperty=nameWithType>:
592+
593+
* When `false`, display a loading indicator.
590594
* When `true`, render the requested component's content.
591595

592-
The following demonstration uses the loading progress indicator found in apps created from the Blazor WebAssembly template, including a modification of the styles that the template provides. The styles are loaded into the app's `<head>` content by the <xref:Microsoft.AspNetCore.Components.Web.HeadContent> component. For more information, see <xref:blazor/components/control-head-content>.
596+
If you wish to load styles for the indicator, add them to `<head>` content with the <xref:Microsoft.AspNetCore.Components.Web.HeadContent> component. For more information, see <xref:blazor/components/control-head-content>.
593597

594-
`LoadingProgress.razor`:
598+
`Layout/ContentLoading.razor`:
595599

596600
```razor
597601
@if (!OperatingSystem.IsBrowser())
598602
{
603+
<!-- OPTIONAL ...
599604
<HeadContent>
600605
<style>
601-
.loading-progress {
602-
position: relative;
603-
display: block;
604-
width: 8rem;
605-
height: 8rem;
606-
margin: 20vh auto 1rem auto;
607-
}
608-
609-
.loading-progress circle {
610-
fill: none;
611-
stroke: #e0e0e0;
612-
stroke-width: 0.6rem;
613-
transform-origin: 50% 50%;
614-
transform: rotate(-90deg);
615-
}
616-
617-
.loading-progress circle:last-child {
618-
stroke: #1b6ec2;
619-
stroke-dasharray:
620-
calc(3.142 * var(--blazor-load-percentage, 0%) * 0.8),
621-
500%;
622-
transition: stroke-dasharray 0.05s ease-in-out;
623-
}
624-
625-
.loading-progress-text {
626-
position: relative;
627-
text-align: center;
628-
font-weight: bold;
629-
top: -90px;
630-
}
631-
632-
.loading-progress-text:after {
633-
content: var(--blazor-load-percentage-text, "Loading");
634-
}
635-
636-
code {
637-
color: #c02d76;
638-
}
606+
...
639607
</style>
640608
</HeadContent>
641-
<svg class="loading-progress">
642-
<circle r="40%" cx="50%" cy="50%" />
643-
<circle r="40%" cx="50%" cy="50%" />
644-
</svg>
645-
<div class="loading-progress-text"></div>
609+
-->
610+
<div aria-busy="true" aria-describedby="progress-bar" />
611+
<progress id="progress-bar" aria-label="Content loading…"></progress>
646612
}
647613
else
648614
{
@@ -655,7 +621,7 @@ else
655621
}
656622
```
657623

658-
In a component that adopts Interactive WebAssembly rendering, wrap the component's Razor markup with the `LoadingProgress` component. The following example demonstrates the approach with the `Counter` component of an app created from the Blazor Web App project template.
624+
In a component that adopts Interactive WebAssembly rendering, wrap the component's Razor markup with the `ContentLoading` component. The following example demonstrates the approach with the `Counter` component of an app created from the Blazor Web App project template.
659625

660626
`Pages/Counter.razor`:
661627

@@ -665,13 +631,13 @@ In a component that adopts Interactive WebAssembly rendering, wrap the component
665631
666632
<PageTitle>Counter</PageTitle>
667633
668-
<LoadingProgress>
634+
<ContentLoading>
669635
<h1>Counter</h1>
670636
671637
<p role="status">Current count: @currentCount</p>
672638
673639
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
674-
</LoadingProgress>
640+
</ContentLoading>
675641
676642
@code {
677643
private int currentCount = 0;
@@ -683,6 +649,140 @@ In a component that adopts Interactive WebAssembly rendering, wrap the component
683649
}
684650
```
685651

652+
#### Global Interactive WebAssembly rendering with prerendering
653+
654+
*This scenario applies to global Interactive WebAssembly rendering without prerendering (`@rendermode="InteractiveWebAssembly"` on the `HeadOutlet` and `Routes` components in the `App` component).*
655+
656+
Create a `ContentLoading` component in the `Layout` folder of the `.Client` app that calls <xref:Microsoft.AspNetCore.Components.RendererInfo.IsInteractive?displayProperty=nameWithType>:
657+
658+
* When `false`, display a loading progress indicator.
659+
* When `true`, render the requested component's content.
660+
661+
If you wish to load styles for the indicator, add them to `<head>` content with the <xref:Microsoft.AspNetCore.Components.Web.HeadContent> component. For more information, see <xref:blazor/components/control-head-content>.
662+
663+
`Layout/ContentLoading.razor`:
664+
665+
```razor
666+
@if (!RendererInfo.IsInteractive)
667+
{
668+
<!-- OPTIONAL ...
669+
<HeadContent>
670+
<style>
671+
...
672+
</style>
673+
</HeadContent>
674+
-->
675+
<div aria-busy="true" aria-describedby="progress-bar" />
676+
<progress id="progress-bar" aria-label="Content loading…"></progress>
677+
}
678+
else
679+
{
680+
@ChildContent
681+
}
682+
683+
@code {
684+
[Parameter]
685+
public RenderFragment? ChildContent { get; set; }
686+
}
687+
```
688+
689+
In the `MainLayout` component (`Layout/MainLayout.razor`) of the `.Client` project, wrap the <xref:Microsoft.AspNetCore.Components.LayoutComponentBase.Body%2A> property (`@Body`) with the `ContentLoading` component:
690+
691+
In `Layout/MainLayout.razor`:
692+
693+
```diff
694+
+ <ContentLoading>
695+
@Body
696+
+ </ContentLoading>
697+
```
698+
699+
#### Global Interactive WebAssembly rendering without prerendering
700+
701+
*This scenario applies to global Interactive WebAssembly rendering without prerendering (`@rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)"` on the `HeadOutlet` and `Routes` components in the `App` component).*
702+
703+
Create a `ContentLoading` component in the `Layout` folder of the `.Client` app with a `Loading` parameter:
704+
705+
* When `true`, display a loading progress indicator.
706+
* When `false`, render the requested component's content.
707+
708+
If you wish to load styles for the indicator, add them to `<head>` content with the <xref:Microsoft.AspNetCore.Components.Web.HeadContent> component. For more information, see <xref:blazor/components/control-head-content>.
709+
710+
`Layout/ContentLoading.razor`:
711+
712+
```razor
713+
@if (Loading)
714+
{
715+
<!-- OPTIONAL ...
716+
<HeadContent>
717+
<style>
718+
...
719+
</style>
720+
</HeadContent>
721+
-->
722+
<div aria-busy="true" aria-describedby="progress-bar"></div>
723+
<progress id="progress-bar" aria-label="Content loading…"></progress>
724+
}
725+
else
726+
{
727+
@ChildContent
728+
}
729+
730+
@code {
731+
[Parameter]
732+
public RenderFragment? ChildContent { get; set; }
733+
734+
[Parameter]
735+
public bool Loading { get; set; }
736+
}
737+
```
738+
739+
In a component that adopts Interactive WebAssembly rendering without prerendering, wrap the component's Razor markup with the `ContentLoading` component and pass a value in a C# field to the `Loading` parameter when initialization work is performed by the component. The following example demonstrates the approach with the `Home` component of an app created from the Blazor Web App project template.
740+
741+
`Pages/Home.razor`:
742+
743+
```diff
744+
@page "/"
745+
746+
<PageTitle>Home</PageTitle>
747+
748+
<ContentLoading Loading="@loading">
749+
<h1>Hello, world!</h1>
750+
<p>Welcome to your new app.</p>
751+
</ContentLoading>
752+
753+
@code {
754+
private bool loading = true;
755+
756+
protected override async Task OnInitializedAsync()
757+
{
758+
// Simulate long-running work
759+
await Task.Delay(5000);
760+
761+
loading = false;
762+
}
763+
}
764+
```
765+
766+
This approach also works with the [cancelable background work pattern](xref:blazor/components/lifecycle#cancelable-background-work):
767+
768+
```razor
769+
<ContentLoading Loading="@loading">
770+
...
771+
</ContentLoading>
772+
773+
@code {
774+
private bool loading = true;
775+
...
776+
777+
protected override async Task OnInitializedAsync()
778+
{
779+
await LongRunningWork().ContinueWith(_ => loading = false);
780+
}
781+
782+
...
783+
}
784+
```
785+
686786
### Blazor WebAssembly app loading progress
687787

688788
:::moniker-end

0 commit comments

Comments
 (0)