Adding Superpowers to your Blazor WebAssembly App with Project Fugu APIs

Blazor WebAssembly is a powerful framework for building web applications that run on the client-side. With Project Fugu APIs, you can extend the capabilities of these apps to access new device features and provide an enhanced user experience. In this article, learn about the benefits of using Project Fugu APIs, the wrapper packages that are available for Blazor WebAssembly, and how to use them in your application.

Whether you're a seasoned Blazor developer or just getting started, this article will help you add superpowers to your Blazor WebAssembly app.

In this article:

Christian Liebel is consultant at Thinktecture, focuses on web standards and Progressive Web Applications, and is Thinktecture's representative at the W3C.

Blazor WebAssembly is Microsoft’s framework for building single-page apps (SPAs) with C# and Razor. You can use Blazor to build more or less the same experiences as with other SPA frameworks such as React or Angular. This includes Progressive Web Apps (PWA)—web-based applications that work offline and can be installed on the user’s system.

Project Fugu, a joint venture between Microsoft, Google, Intel, and others, wants to bring more capabilities to the web to make PWAs and other web-based applications even more powerful. This includes accessing the file system, displaying app badges, or registering a web app as a handler for specific file extensions. As web platform APIs are for everyone, they can also be used within Blazor WebAssembly applications.

A graphic showing the Project Fugu mascot, a puffer fish, in the center. From there, Fugu APIs are represented by an icon in each of four directions: The File System Access API, the Async Clipboard API, the Web Share API, and the Badging API.
The puffer fish is the mascot of the Fugu Initiative.

However, those APIs are typically JavaScript-based. To access them within Blazor WebAssembly apps, they must be wrapped for .NET. Some ready-to-use open-source NuGet packages exist, but my Thinktecture colleague Patrick Jahr and I missed some APIs. So, over the last couple of weeks, we implemented several missing Fugu wrappers for Blazor WebAssembly. You can find the source code and all samples on GitHub:

This blog post will introduce some of the new web platform APIs, including their browser and platform support, and explains how to use the Blazor WebAssembly wrapper packages provided by the community and us. Please note that our packages are technical showcases and not official Thinktecture products.

Stay backwards compatible with Progressive Enhancement

Before using any of the following APIs, you should always check if it is available on the target system, as the platform support varies. Calling a non-existing API will lead to an error during runtime, and the application may crash. To avoid this, all wrapper packages discussed in this blog post offer a method called IsSupportedAsync() returning a boolean value whether the API is available:

					var isSupported = await badgingService.IsSupportedAsync();
if (isSupported)
    // enable badging feature
    // use fallback mechanism or hide/disable feature

In case the API is not available on the user’s system, you should hide or disable the feature. In some cases, alternative implementations are available to achieve similar behavior.

Share content to other apps with the Web Share API

The Web Share API allows you to share a title, URL, text, or files with another application installed on the user’s system via the share functionality provided by the operating system.

A screenshot of a platform-specific share dialog on top of a Blazor WebAssembly application.
Thanks to the Web Share API, Blazor WebAssembly apps can share data using the platform-specific share sheet.

To use this API from your Blazor WebAssembly application, install the wrapper NuGet package for the Web Share API by using the following command:

					dotnet add package Thinktecture.Blazor.WebShare

Before using the API, you have to add the WebShareService to the IServiceCollection in Program.cs as follows:


Now, you can inject the WebShareService into your Blazor component. By calling its ShareAsync() method and passing a WebShareDataModel object to it, the device’s share sheet will open. The user can select an already installed application to share the content with or send it to another device via nearby sharing or AirDrop.

    var data = new WebShareDataModel
        Title = "Test 1",
        Text = "Lorem ipsum dolor...",
        Url = ""
    await webShareService.ShareAsync(data);
catch (Exception ex)
    // data not shareable or user denied sharing

Please note that the API is only exposed on secure contexts (sites transferred via HTTPS and localhost) and can only be invoked due to user interaction (i.e., a keypress or click). This also applies to most other APIs in this article. If the data cannot be shared or the user has dismissed the share sheet, an exception will be thrown.

Details about sharing files can be found in the readme file of the Web Share API wrapper package.

The Web Share API is supported by Chrome 89, Edge 81, and Safari 12.1. Mozilla Firefox also supports the API, but only on Android. For more details, see the browser support table for the Web Share API on

Access the clipboard via the Async Clipboard API

The Async Clipboard API allows you to read and write text, images, and other data from or to the system’s clipboard. The supported data formats depend on the target platform. For instance, WebKit currently only supports plain text, HTML, URI lists, and PNG images.

You can install this wrapper package by using the following command:

					dotnet add package Thinktecture.Blazor.AsyncClipboard

Before using the API, you have to add the service to your service collection:


Afterward, you can inject the service into your Blazor component. It offers two shorthand methods for writing and reading plain text to or from the clipboard:

					// Write plain text to the clipboard
await asyncClipboardService.WriteTextAsync("Hello world");

// Read plain text from the clipboard
var text = await asyncClipboardService.ReadTextAsync();

The service also offers WriteAsync() and ReadAsync() methods for dealing with arbitrary data, if supported by the target platform. The readme file of the Async Clipboard API wrapper package explains those two methods in more detail.

Depending on the platform and action, permission or confirm prompts may open.

A screenshot of a browser showing a clipboard permission prompt on top of a Blazor WebAssembly application.
Due to security and privacy considerations, Chrome prompts the user for permission before giving the web application read access to the clipboard.

The Async Clipboard API is supported since Microsoft Edge 79, Google Chrome 62, and Apple Safari 13.1. Mozilla Firefox only supports writing plain text, since version 63. For more details, see the browser support table for the Async Clipboard API on

Opening and saving files with the File System Access API

The File System Access API allows your app to open, modify, and save local files and directories. It is based on the more general File System API and specifically deals with the local file system. This allows developers to finally bring traditional productivity apps to the web, such as image editors, word processors, or IDEs. For instance, the web-based version of Visual Studio Code uses this API to access local code workspaces.

Kristoffer Strube maintains wrappers for both the File System API and the File System Access API. His implementations inspired all our wrappers, and some rely on his packages. We want to take this opportunity to thank Kristoffer for the great collaboration so far.

To install this wrapper, run the following command:

					dotnet add package KristofferStrube.Blazor.FileSystemAccess

Next, the File System Access API service needs to be added to your service collection:


Now you can inject the IFileSystemAccessService into your Blazor component or service. To get a file handle, call the ShowOpenFilePickerAsync() method. If the user selects a file via the file picker, it will then be passed to the application, where you can access its contents:

    var fileHandles = await _fas.ShowOpenFilePickerAsync();
    var fileHandle = fileHandles.Single();
    var file = await fileHandle.GetFileAsync();
    var text = await file.TextAsync();
catch (Exception ex)
    // API not available, user denied request or file could not be opened/read

With the help of the file handle, you can also modify its contents. Additional usages of this API and package are shown in the readme file of the File System Access API wrapper package.

A screenshot showing a file open dialog box on top of a Blazor WebAssembly application.
Thanks to the File System Access API, Blazor WebAssembly apps can open and modify files from the local file system.

The File System Access API is supported by Chromium-based browsers only: Microsoft Edge and Google Chrome since version 86. Browser vendors can decide to disable the API, though. For example, Brave chose not to support the API, although this browser is also Chromium-based. Apple Safari only supports the File System API with the Origin Private File System (OPFS), an isolated file system that isn’t mapped to the local one. Mozilla Firefox supports neither of them. For more details, see the browser support table for the File System Access API on If you need to support all browsers, refer to fallback approaches.

Registering your app as a file editor via File Handling

The File Handling API is built on top of the File System API. It allows your PWA to register as a file handler for specific file types. This requires your app to be installed on the user’s system, as the app has to register its name and icon with the operating system. On desktop systems, installation is currently only supported by Chromium-based browsers.

To use the File Handling API in your Blazor WebAssembly app, install the following NuGet package:

					dotnet add package Thinktecture.Blazor.FileHandling

Next, you need to add the file handling service to the service collection:


In contrast to all other APIs, the File Handling API has an imperative and a declarative part. To be registered as a file handler on installation, you must declare the file_handlers property in your application’s Web Application Manifest:

  "file_handlers": [{
    "action": "./",
    "accept": {
      "text/plain": [".txt"]

This property takes an array of file handlers which must include an action (the URL that should be called if the application is invoked as a file handler) and an accept object. This object maps the list of file extensions to a media type. A handler can deal with more than one media type and file extension. Optionally, you can also specify an icon for this file type.

A screenshot showing a Windows Explorer window with a context menu for a text file. A Blazor WebAssembly app appears as a compatible program.
The Blazor WebAssembly app appears in the list of compatible editing programs.

The second part involves adding code to your application: This code is executed when your application is launched as a file handler. Therefore, we are exposing the method SetConsumerAsync() on the FileHandlingService. This method takes a callback with launch parameters. The callback is invoked if the application was launched as a file handler. It will then expose the file handles on the Files property. The type is fully compatible with the File System Access API types.

					await _fileHandlingService.SetConsumerAsync(async (launchParams) =>
    foreach (var fileSystemHandle in launchParams.Files)
        if (fileSystemHandle is FileSystemFileHandle fileSystemFileHandle)
            var file = await fileSystemFileHandle.GetFileAsync();
            var text = await file.TextAsync();

Using the file handles, the application can access the files’ contents and display them during runtime.

A screenshot of a Blazor WebAssembly application displaying text from a local file.
The Blazor WebAssembly app has gained access to the content of a file it was opened with.

The File Handling API is only supported by Chromium-based browsers since version 102 (see Chrome 102 release notes).

Communicate unfinished tasks via the Badging API

The Badging API allows you to display a badge on the installed application’s icon as a less obtrusive alternative to notification banners. The badges are well known from applications like email clients, instant messengers, or to-do apps. This also requires your application to be installed so it has an icon in the taskbar or dock.

To use this API, install the following wrapper package:

					dotnet add package Thinktecture.Blazor.Badging

As always, the services needs to be added to the service collection:

To set a badge on the application’s icon, call the SetAppBadgeAsync() method. This method takes a number that will be shown on the badge. You can also set it to null. In this case, a generic badge will be shown (without a number).
					await badgingService.SetAppBadgeAsync(3);
A screenshot showing a Blazor WebAssembly application and the Windows taskbar. The application's icon has a little badge with the number 3 on it.
Thanks to the Badging API, Blazor WebAssembly applications can display badges on their app icons.

To remove the badge again, for example, when all email messages are read, all instant messages are answered, or all todo items are done, simply call the ClearAppBadgeAsync() method:

					await badgingService.ClearAppBadgeAsync();

The Badging API is currently only supported by Chromium-based browsers since version 81 on macOS and Windows, and by Apple Safari on iOS and iPadOS starting from version 16.4 Beta 1 (as long as the application has been added to the home screen and has permission for receiving push notifications). For more details, see the browser support table for the setAppBadge() method on

Powerful APIs for a more capable web

The new web platform APIs introduced by Project Fugu make web applications significantly more powerful, including your Blazor WebAssembly apps. Using the wrapper packages provided by the community and us, you can genuinely add superpowers to your Blazor-based web apps. We look forward to your feedback and are eager to see where our packages will be used. Keep an eye on our blog for more wrapper packages and updates on Progressive Web Apps. So let’s go and make the web a more powerful place!


Current articles, screencasts and interviews by our experts

Don’t miss any content on Angular, .NET Core, Blazor, Azure, and Kubernetes and sign up for our free monthly dev newsletter.

EN Newsletter Anmeldung (#7)
Related Articles
One of the more pragmatic ways to get going on the current AI hype, and to get some value out of it, is by leveraging semantic search. This is, in itself, a relatively simple concept: You have a bunch of documents and want to find the correct one based on a given query. The semantic part now allows you to find the correct document based on the meaning of its contents, in contrast to simply finding words or parts of words in it like we usually do with lexical search. In our last projects, we gathered some experience with search bots, and with this article, I'd love to share our insights with you.
If you previously wanted to integrate view transitions into your Angular application, this was only possible in a very cumbersome way that needed a lot of detailed knowledge about Angular internals. Now, Angular 17 introduced a feature to integrate the View Transition API with the router. In this two-part series, we will look at how to leverage the feature for route transitions and how we could use it for single-page animations.
.NET 8 brings Native AOT to ASP.NET Core, but many frameworks and libraries rely on unbound reflection internally and thus cannot support this scenario yet. This is true for ORMs, too: EF Core and Dapper will only bring full support for Native AOT in later releases. In this post, we will implement a database access layer with Sessions using the Humble Object pattern to get a similar developer experience. We will use Npgsql as a plain ADO.NET provider targeting PostgreSQL.