Skip to content

Commit acffa6e

Browse files
authored
Custom Blazor WASM loading progress indicator (#31145)
1 parent a326006 commit acffa6e

File tree

2 files changed

+129
-1
lines changed

2 files changed

+129
-1
lines changed

aspnetcore/blazor/components/rendering.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,10 @@ For approaches to manage state, see the following resources:
265265
For the state manager approach, C# events are outside the Blazor rendering pipeline. Call <xref:Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged%2A> on other components you wish to rerender in response to the state manager's events.
266266

267267
The state manager approach is similar to the earlier case with <xref:System.Timers.Timer?displayProperty=fullName> in the [previous section](#receiving-a-call-from-something-external-to-the-blazor-rendering-and-event-handling-system). Since the execution call stack typically remains on the renderer's synchronization context, calling <xref:Microsoft.AspNetCore.Components.ComponentBase.InvokeAsync%2A> isn't normally required. Calling <xref:Microsoft.AspNetCore.Components.ComponentBase.InvokeAsync%2A> is only required if the logic escapes the synchronization context, such as calling <xref:System.Threading.Tasks.Task.ContinueWith%2A> on a <xref:System.Threading.Tasks.Task> or awaiting a <xref:System.Threading.Tasks.Task> with [`ConfigureAwait(false)`](xref:System.Threading.Tasks.Task.ConfigureAwait%2A). For more information, see the [Receiving a call from something external to the Blazor rendering and event handling system](#receiving-a-call-from-something-external-to-the-blazor-rendering-and-event-handling-system) section.
268+
269+
## WebAssembly loading progress indicator for Blazor Web Apps
270+
271+
<!-- UPDATE 9.0 Will be removed for a new feature in this area.
272+
Tracked by: https://github.com/dotnet/aspnetcore/issues/49056 -->
273+
274+
A loading progress indicator isn't present in an app created from the Blazor Web App project template. A new loading progress indicator feature is planned for a future release of .NET. In the meantime, an app can adopt custom code to create a loading progress indicator. For more information, see <xref:blazor/fundamentals/startup#client-side-loading-progress-indicators>.

aspnetcore/blazor/fundamentals/startup.md

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,128 @@ For more information on CSPs, see <xref:blazor/security/content-security-policy>
522522

523523
## Client-side loading progress indicators
524524

525-
*This section only applies to Blazor WebAssembly apps.*
525+
A loading progress indicator shows the loading progress of the app to users, indicating that the app is loading normally and that the user should wait until loading is finished.
526+
527+
:::moniker-end
528+
529+
:::moniker range=">= aspnetcore-8.0"
530+
531+
### Blazor Web App loading progress
532+
533+
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:
534+
535+
* Showing multiple loading indicators on the same rendered page.
536+
* Inadvertently discarding prerendered content while the WebAssembly runtime is loading.
537+
538+
<!-- UPDATE 9.0 Will be removed for a new feature in this area.
539+
Tracked by: https://github.com/dotnet/aspnetcore/issues/49056 -->
540+
541+
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.
542+
543+
Create a `LoadingProgress` component in the `.Client` app that calls <xref:System.OperatingSystem.IsBrowser%2A?displayProperty=nameWithType>:
544+
545+
* When `false`, display a loading progress indicator while the Blazor bundle is downloaded and before the Blazor runtime activates on the client.
546+
* When `true`, render the requested component's content.
547+
548+
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>.
549+
550+
`LoadingProgress.razor`:
551+
552+
```razor
553+
@if (!OperatingSystem.IsBrowser())
554+
{
555+
<HeadContent>
556+
<style>
557+
.loading-progress {
558+
position: relative;
559+
display: block;
560+
width: 8rem;
561+
height: 8rem;
562+
margin: 20vh auto 1rem auto;
563+
}
564+
565+
.loading-progress circle {
566+
fill: none;
567+
stroke: #e0e0e0;
568+
stroke-width: 0.6rem;
569+
transform-origin: 50% 50%;
570+
transform: rotate(-90deg);
571+
}
572+
573+
.loading-progress circle:last-child {
574+
stroke: #1b6ec2;
575+
stroke-dasharray:
576+
calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8),
577+
500%;
578+
transition: stroke-dasharray 0.05s ease-in-out;
579+
}
580+
581+
.loading-progress-text {
582+
position: relative;
583+
text-align: center;
584+
font-weight: bold;
585+
top: -90px;
586+
}
587+
588+
.loading-progress-text:after {
589+
content: var(--blazor-load-percentage-text, "Loading");
590+
}
591+
592+
code {
593+
color: #c02d76;
594+
}
595+
</style>
596+
</HeadContent>
597+
<svg class="loading-progress">
598+
<circle r="40%" cx="50%" cy="50%" />
599+
<circle r="40%" cx="50%" cy="50%" />
600+
</svg>
601+
<div class="loading-progress-text"></div>
602+
}
603+
else
604+
{
605+
@ChildContent
606+
}
607+
608+
@code {
609+
[Parameter]
610+
public RenderFragment? ChildContent { get; set; }
611+
}
612+
```
613+
614+
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.
615+
616+
`Pages/Counter.razor`:
617+
618+
```razor
619+
@page "/counter"
620+
@rendermode InteractiveWebAssembly
621+
622+
<PageTitle>Counter</PageTitle>
623+
624+
<LoadingProgress>
625+
<h1>Counter</h1>
626+
627+
<p role="status">Current count: @currentCount</p>
628+
629+
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
630+
</LoadingProgress>
631+
632+
@code {
633+
private int currentCount = 0;
634+
635+
private void IncrementCount()
636+
{
637+
currentCount++;
638+
}
639+
}
640+
```
641+
642+
### Blazor WebAssembly app loading progress
643+
644+
:::moniker-end
645+
646+
:::moniker range=">= aspnetcore-7.0"
526647

527648
The project template contains Scalable Vector Graphics (SVG) and text indicators that show the loading progress of the app.
528649

0 commit comments

Comments
 (0)