Telerik blogs

Through progressive enhancement using enhanced navigation and form handling, Blazor is able to minimize page load times and balance performance while minimizing trade-offs.

In .NET 8, Microsoft improved on Blazor’s performance and user experience by introducing static server-side rendering (static SSR) capabilities. With static SSR, Blazor applications adopt a progressive enhancement strategy by rendering traditional non-interactive HTML pages and forms that incrementally scale to full interactivity. In this article, we’ll explore the enhanced navigation and form-handling feature that bridges the gap between static and interactive pages.

Static SSR and Progressive Enhancement

Prior to .NET 8, Blazor developers had to choose between two distinct interactivity modes using either Blazor WebAssembly or Blazor Server (WebSockets). Each interactivity mode comes with its own performance trade-offs. Applications using Blazor WebAssembly must download additional resources before pages can become interactive causing slower initial startup times. Choosing Blazor Server means applications start up quickly but must maintain a WebSocket connection at all times.

With neither option being ideal, in .NET 8 Microsoft introduced static SSR and Progressive Enhancement to bridge the gap and reduce the trade-off between each option. In addition, interactivity modes are not only optional, but can be set on a page and per-component basis.

For more details on interactivity modes see, Getting Started with Blazor’s New Render Modes in .NET 8.

Since the introduction of ASP.NET MVC, Razor Views (.cshtml) have been served statically rendered as HTML with speed and efficiency. However, there is a notable implementation difference with Razor Views and Razor Components (.razor). Razor Views were created with the intention of rendering an HTML string, whereas Razor Components were designed to mirror the browsers DOM as a RenderTree. The RenderTree object is used with a diffing operation to perform DOM updates. The initial design for Razor Components was not for static rendering, but interactivity. With ASP.NET in .NET 8, Razor Components can also be statically rendered similar to Razor Views. This means with .NET 8 Blazor applications can harness the speed of ASP.NET through static SSR.

With static SSR pages are delivered to the browser as HTML and act like traditional HTML pages. Static rendered pages are not interactive and will perform a full HTTP POST to load new pages or perform form submissions. Static SSR trades the seamless user experience of a single page application (SPA) for speed and simplicity. Instead of creating another rendering choice that leads to a negative trade-off Blazor uses progressive enhancement to create a sliding scale between static HTML and full SPA.

Interactivity Modes

The topic of enhanced navigation and form handling only applies to pages using static SSR. Pages or applications that define an interactive mode will utilize the SPA navigation and interactivity to achieve the same results.

Enhanced Navigation

Using static SSR pages introduces the classic problem of full-page refreshes. When users interact with a static page, the browser must render an entire new page for even the smallest update. In addition, this can cause users to lose scroll position with forms and possibly a momentary flash of a blank screen as the new page loads.

Enhanced navigation takes an incremental approach to fix this problem without requiring a full SPA implementation. Blazor’s enhanced navigation uses client-side JavaScript code included in blazor.web.js to intercept navigation requests, fetch the new page and patch changes back to the DOM.

Blazor’s enhanced navigation is on by default and enabled when the Blazor Web App script blazor.web.js is used. Enhanced Navigation is not included the Blazor Server script blazor.server.js or Blazor WebAssembly script blazor.webassembly.js. When enhanced navigation is enabled, the Blazor app will perform the following actions:

  1. Interception: When a request is made to a Blazor-enabled resource, Blazor intercepts it. If the destination is a non-Blazor endpoint, enhanced navigation doesn’t apply, and the client-side JavaScript retries as a full-page load. This ensures no confusion to the framework about external pages that shouldn’t be patched into an existing page.
  2. Fetch request: Instead of triggering a full-page reload, Blazor performs a fetch request using the browser’s Fetch API.
  3. DOM patching: The rendered response content is then handled by Blazor patching it into the browser’s Document Object Model (DOM). Internally blazor.web.js implements a Levenshtein distance calculation to determine the most efficient method of patching the the DOM (Keep, Update, Insert or Delete). DOM patching allows Blazor to update the page without redrawing the entire screen minimizing rendering time.

The enhanced navigation feature provides an ideal experience for most solutions. However, if the feature is not desired, it can be disabled.

Disabling Enhanced Navigation

Pages that use JavaScript libraries to make changes to the DOM may interfere with enhanced navigation or cause instability. The feature can be controlled globally, hierarchically and on a per-link basis to deal with these scenarios.

To disable enhanced navigation and form handling, set disableDomPreservation to true for Blazor.start.

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    ssr: { disableDomPreservation: true }
  });
</script>

In the preceding example, the {BLAZOR SCRIPT} placeholder is the Blazor script path and file name. For the location of the script, see ASP.NET Core Blazor project structure.

The following examples disable enhanced navigation using the data-enhance-nav attribute. Below, data-enhance-nav="false" disables the feature for a single link instance.

<a href="redirect" data-enhance-nav="false">
    GET without enhanced navigation
</a>

The next example demonstrates how using element hierarchy can disable multiple elements. In the snippet below, enhanced navigation is disabled for all links because they are children of the nav where data-enhance-nav="false" is set.

<ul data-enhance-nav="false">
    <li>
        <a href="redirect">GET without enhanced navigation</a>
    </li>
    <li>
        <a href="redirect-2">GET without enhanced navigation</a>
    </li>
</ul>

Enhanced navigation is a great way to progressively improve the user experience of a Blazor app. With .NET 8, the feature comes enabled out of the box but can be configured easily through global or per-element syntax. Forms can also be enhanced with similar capabilities; however, enhanced form handling must be opted in to.

Enhanced Form Handling

When Blazor is using static SSR, forms will initiate a standard POST request. When the server responds, the page will be completely replaced to update and display the results. To eliminate the full-page refresh caused by forms, Blazor apps can enable enhanced form handling.

Static SSR forms can be written using almost identical code to those using interactivity. Statically rendered forms will post and validate as expected, requiring a few minor changes. In order to bind values from a static form post correctly, the desired parameters must use the [SupplyParametersFromForm] attribute. In addition, since form posts are more complex than navigation, we must explicitly enable the feature.

Enhanced form handling is enabled only by the EditForm component’s Enhance property or <form> element by using the data-enhance attribute. Unlike enhanced navigation, enhanced form handling isn’t hierarchical and doesn’t flow to child forms.

In the snippet below, enhanced form handling is enabled by setting the Enhance property. The default value is true and may either be set to false or removed to disable the feature.

<EditForm Enhance ...>
    ...
</EditForm>

In the following snippet, enhanced form handling is enabled by setting the data-enhance attribute on a form element. The default value is true and may either be set to false or removed to disable the feature.

<form ... data-enhance>
    ...
</form>

Enhanced form posts only work with Blazor endpoints. Posting an enhanced form to non-Blazor endpoint results in an error.

When an enhanced form submits a request, Blazor will intercept the request, perform the form action and patch changes back to the DOM. The page is updated without redrawing the entire screen, saving time and user’s scroll position.

Enhanced forms are compatible with streaming rendering. Streaming rendering enables a SPA-like experience with long-running processes. By combining enhanced forms with streaming rendering, a progress indicator can be shown while awaiting a form post without needing interactivity.

@attribute [StreamingRendering] <EditForm Enhance FormName="create-product" method="post" Model="@Item" OnValidSubmit="SaveProduct"> <p>Name: <InputText @bind-Value="@Item.Name"/></p> <p>Price: $<InputNumber @bind-Value="@Item.Price"/></p> <button>submit</button> <DataAnnotationsValidaton/> <ValidationSummary /> </EditForm> @code { string? message; [SupplyParameterFromForm] public Product Item { get;set; } = new(); private async Task SaveProductAsync() { message = $"Saving..."; await DataStore.AddProductAsync(Item); message = $"Product added"; } }

An animation showing the enhanced form handling

Conclusion

Blazor in .NET 8 brings traditional HTML and HTTP concepts together with modern techniques to enable a sliding scale between static pages and full SPAs. Through progressive enhancement using enhanced navigation and form handling, Blazor is able to minimize page load times and balance performance while minimizing trade-offs.

Use a component library in sync with Microsoft’s release cadence. Telerik UI for Blazor offers more than 110 truly native Blazor components to make it fast and easy to develop new Blazor apps or modernize legacy apps. Try it free for 30 days.

About the Author

Ed Charbeneau

Ed Charbeneau is a web enthusiast, speaker, writer, design admirer, and Developer Advocate for Telerik. He has designed and developed web based applications for business, manufacturing, systems integration as well as customer facing websites. Ed enjoys geeking out to cool new tech, brainstorming about future technology, and admiring great design. Ed's latest projects can be found on GitHub.

Related Posts

Comments

Comments are disabled in preview mode.