SpawnDev.BlazorJS
3.5.3
dotnet add package SpawnDev.BlazorJS --version 3.5.3
NuGet\Install-Package SpawnDev.BlazorJS -Version 3.5.3
<PackageReference Include="SpawnDev.BlazorJS" Version="3.5.3" />
<PackageVersion Include="SpawnDev.BlazorJS" Version="3.5.3" />
<PackageReference Include="SpawnDev.BlazorJS" />
paket add SpawnDev.BlazorJS --version 3.5.3
#r "nuget: SpawnDev.BlazorJS, 3.5.3"
#:package SpawnDev.BlazorJS@3.5.3
#addin nuget:?package=SpawnDev.BlazorJS&version=3.5.3
#tool nuget:?package=SpawnDev.BlazorJS&version=3.5.3
SpawnDev.BlazorJS
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.
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 methodsPlaywrightTestRunner- Playwright test runner projectPlaywrightTestRunner/_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!
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 | Versions 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. |
-
net10.0
- Microsoft.AspNetCore.Components.WebAssembly (>= 10.0.0)
- SpawnDev.BackgroundServices (>= 1.0.2)
-
net8.0
- Microsoft.AspNetCore.Components.WebAssembly (>= 8.0.19)
- SpawnDev.BackgroundServices (>= 1.0.2)
-
net9.0
- Microsoft.AspNetCore.Components.WebAssembly (>= 9.0.8)
- SpawnDev.BackgroundServices (>= 1.0.2)
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 |