SpawnDev.BlazorJS 3.5.3

dotnet add package SpawnDev.BlazorJS --version 3.5.3
                    
NuGet\Install-Package SpawnDev.BlazorJS -Version 3.5.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SpawnDev.BlazorJS" Version="3.5.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SpawnDev.BlazorJS" Version="3.5.3" />
                    
Directory.Packages.props
<PackageReference Include="SpawnDev.BlazorJS" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SpawnDev.BlazorJS --version 3.5.3
                    
#r "nuget: SpawnDev.BlazorJS, 3.5.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SpawnDev.BlazorJS@3.5.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SpawnDev.BlazorJS&version=3.5.3
                    
Install as a Cake Addin
#tool nuget:?package=SpawnDev.BlazorJS&version=3.5.3
                    
Install as a Cake Tool

SpawnDev.BlazorJS

NuGet

Full Blazor WebAssembly and JavaScript interop. Over 1,000 strongly typed C# wrappers for browser APIs - create JavaScript objects, access properties, call methods, and handle events the .NET way without writing JavaScript.

Full API Documentation - Complete MDN-style API reference with guides, 1,000+ typed wrapper references, and real C# examples.

Live Demo

Supported .NET Versions

  • .NET 8, 9, and 10
  • Blazor WebAssembly Standalone App
  • Blazor Web App - Interactive WebAssembly mode without prerendering

Note: Version 3.x dropped support for .NET 6 and 7. Use version 2.x for those targets.

Important: PublishTrimmed and RunAOTCompilation must be set to false in your project file. Trimming removes types needed for JS interop.

SpawnDev.BlazorJS.WebWorkers is now in a separate repo.

Installation

dotnet add package SpawnDev.BlazorJS

Quick Start

Two changes to Program.cs:

using SpawnDev.BlazorJS;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

// Add BlazorJSRuntime
builder.Services.AddBlazorJSRuntime();

// Use BlazorJSRunAsync instead of RunAsync
await builder.Build().BlazorJSRunAsync();

Inject into any component or service:

[Inject]
BlazorJSRuntime JS { get; set; }

Basic usage:

// Get and Set global properties
var innerHeight = JS.Get<int>("window.innerHeight");
JS.Set("document.title", "Hello World!");

// Call global methods
var item = JS.Call<string?>("localStorage.getItem", "key");
JS.CallVoid("console.log", "Hello from Blazor!");

// Async methods (Promise-returning)
var response = await JS.CallAsync<Response>("fetch", "/api/data");

// Create new JS objects
using var audio = new Audio("song.mp3");
await audio.Play();

// Typed browser API access
using var window = JS.Get<Window>("window");
window.OnResize += Window_OnResize;
// ... later, before disposing:
window.OnResize -= Window_OnResize;

void Window_OnResize() => Console.WriteLine("Window resized!");

// Null-conditional member access
var size = JS.Get<int?>("fruit.options?.size");

For full setup details including worker scope detection and WebWorkerService, see the Getting Started Guide.


Key Features

Feature Description Docs
1,000+ Typed Wrappers Every major browser API - DOM, WebGPU, WebRTC, WebAudio, Crypto, WebXR, and more API Reference
BlazorJSRuntime Get, Set, Call, CallAsync, New - with null-conditional (?.) support Guide
JSObject Base class for typed JS wrappers with automatic disposal Guide
ActionEvent Type-safe event subscription with += / -= and automatic ref counting Guide
Callbacks Pass .NET methods to JS - Create, CreateOne, CallbackGroup Guide
Union Types TypeScript-style discriminated unions with Match, Map, Reduce Guide
Undefinable Distinguish null from undefined in JS interop Guide
TypedArrays Full typed array support - Uint8Array, Float32Array, ArrayBuffer, etc. Guide
HeapView Zero-copy data sharing by pinning .NET arrays in WASM memory Guide
Promises JS Promise wrapper - create from Task, lambda, or TaskCompletionSource Guide
Worker Scopes Detect Window, DedicatedWorker, SharedWorker, ServiceWorker contexts Guide
Custom Wrappers Wrap any JS library in typed C# - step-by-step guide Guide
Disposal Managing JSObject, Callback, and reference lifetimes Guide
EnumString Bidirectional enum-to-JS-string mapping Guide
Blazor Web App .NET 8+ compatibility with prerendering support Guide

Sync vs Async - Important

SpawnDev.BlazorJS is a 1:1 mapping to JavaScript. Use the correct call type or it will throw:

JS Method Returns C# Call Wrong
Value (sync) JS.Call<T>(), JS.Get<T>() CallAsync on sync method throws
Promise (async) JS.CallAsync<T>() Call on Promise returns wrong type
void (sync) JS.CallVoid() -
void Promise (async) JS.CallVoidAsync() CallVoid on async method won't await
// Sync JS method - use sync call
var total = JS.Call<int>("addNumbers", 20, 22);

// Async JS method or Promise-returning - use async call
var data = await JS.CallAsync<string>("fetchData");

// Async void (Promise with no return value)
await JS.CallVoidAsync("someAsyncVoidMethod");

See the BlazorJSRuntime Guide for full details.


Browser API Examples

WebSocket

using var ws = new WebSocket("wss://echo.websocket.org");
ws.BinaryType = "arraybuffer";
ws.OnOpen += WS_OnOpen;
ws.OnMessage += WS_OnMessage;
ws.OnClose += WS_OnClose;

// ... when done, always unsubscribe before disposing:
ws.OnOpen -= WS_OnOpen;
ws.OnMessage -= WS_OnMessage;
ws.OnClose -= WS_OnClose;

void WS_OnOpen() => ws.Send("Hello!");
void WS_OnMessage(MessageEvent msg) => Console.WriteLine($"Received: {msg.Data}");
void WS_OnClose(CloseEvent e) => Console.WriteLine($"Closed: {e.Code}");

Fetch API

using var response = await JS.CallAsync<Response>("fetch", "/api/data");
if (response.Ok)
{
    var text = await response.Text();
    Console.WriteLine(text);
}

IndexedDB

using var idbFactory = new IDBFactory();
using var db = await idbFactory.OpenAsync("myDB", 1, (evt) =>
{
    using var request = evt.Target;
    using var database = request.Result;
    database.CreateObjectStore<string, MyData>("store", new IDBObjectStoreCreateOptions { KeyPath = "id" });
});
using var tx = db.Transaction("store", "readwrite");
using var store = tx.ObjectStore<string, MyData>("store");
await store.PutAsync(new MyData { Id = "1", Name = "Test" });

Web Crypto

using var crypto = new Crypto();
using var subtle = crypto.Subtle;
using var keys = await subtle.GenerateKey<CryptoKeyPair>(
    new EcKeyGenParams { Name = "ECDSA", NamedCurve = "P-384" },
    false, new[] { "sign", "verify" });
using var signature = await subtle.Sign(
    new EcdsaParams { Hash = "SHA-384" }, keys.PrivateKey!, testData);
var valid = await subtle.Verify(
    new EcdsaParams { Hash = "SHA-384" }, keys.PublicKey!, signature, testData);

ActionEvent (Event Handling)

using var window = JS.Get<Window>("window");

// Attach event handler - reference counting is automatic
window.OnStorage += HandleStorageEvent;

// Detach - IMPORTANT: always detach before disposing to prevent leaks
window.OnStorage -= HandleStorageEvent;

void HandleStorageEvent(StorageEvent e)
{
    Console.WriteLine($"Storage changed: {e.Key}");
}

Custom JSObject Wrapper

// Wrap any JS library without writing JavaScript
public class Audio : JSObject
{
    public Audio(IJSInProcessObjectReference _ref) : base(_ref) { }
    public Audio(string url) : base(JS.New("Audio", url)) { }
    
    public string Src { get => JSRef!.Get<string>("src"); set => JSRef!.Set("src", value); }
    public double Volume { get => JSRef!.Get<double>("volume"); set => JSRef!.Set("volume", value); }
    public Task Play() => JSRef!.CallVoidAsync("play");
    public Task Pause() => JSRef!.CallVoidAsync("pause");
    
    public ActionEvent OnEnded { get => new ActionEvent("ended", AddEventListener, RemoveEventListener); set { } }
}

See the Custom JSObject Guide for the full walkthrough.

For 930+ more typed wrappers, see the Complete API Reference.


Unit Testing

This project uses Playwright .NET for unit testing in a real browser with an actual JavaScript environment.

  • SpawnDev.BlazorJS.Demo - Demo project with unit test methods
  • PlaywrightTestRunner - Playwright test runner project
  • PlaywrightTestRunner/_test.bat / _test.sh - Build and run tests on Windows / Linux
  • .github/workflows/playwright-test-runner.yml - CI testing on GitHub Actions

Issues and Feature Requests

If you find a bug or missing properties, methods, or JavaScript objects please submit an issue here on GitHub. I will help as soon as possible.

Create a new discussion to show off your projects and post your ideas.

Support for Us

Sponsor us via GitHub Sponsors to give us more time to work on SpawnDev.BlazorJS and other open source projects. Or buy us a cup of coffee via PayPal. All support is greatly appreciated!

GitHub Sponsor Donate

Thank you to everyone who has helped support SpawnDev.BlazorJS and related projects financially, by filing issues, and by improving the code. Every bit helps!

Demos

BlazorJS and WebWorkers Demo: https://blazorjs.spawndev.com/

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (28)

Showing the top 5 NuGet packages that depend on SpawnDev.BlazorJS:

Package Downloads
SpawnDev.BlazorJS.WebWorkers

Call Services and static methods in separate threads with WebWorkers and SharedWebWorkers. Run Blazor WASM in the ServiceWorker.

SpawnDev.BlazorJS.WebTorrents

WebTorrents in Blazor WebAssembly

SpawnDev.BlazorJS.Cryptography

A cross platform cryptography library that supports encryption with AES-GCM and AES-CBC, shared secret generation with ECDH, data signatures with ECDSA and Ed25519, and hashing with SHA on Windows, Linux, and Browser (Blazor) platforms.

SpawnDev.BlazorJS.TransformersJS

Use Transformers.js from Blazor WebAssembly to run pretrained models with the ONNX Runtime in the browser.

SpawnDev.BlazorJS.VisNetwork

VisNetwork in Blazor WebAssembly

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.5.3 29 4/16/2026
3.5.2 30 4/16/2026
3.5.1 59 4/14/2026
3.5.0 1,104 3/18/2026
3.4.0 199 3/17/2026
3.3.2 97 3/16/2026
3.3.1 103 3/16/2026
3.3.0 810 3/7/2026
3.2.1 150 3/4/2026
3.2.0 99 3/2/2026
3.1.1 151 2/23/2026
3.1.0 114 2/22/2026
3.0.3 233 2/17/2026
3.0.2 172 2/15/2026
3.0.1 147 2/12/2026
3.0.0 666 2/12/2026
3.0.0-rc.1 51 2/12/2026
2.66.1 116 2/11/2026
2.66.0 240 2/11/2026
2.65.0 244 2/7/2026
Loading failed