Skip to main content

JavaScript Interop Guide

InfiniFrame provides two layers of JS interop:

  1. Web messaging: a versioned message channel between C# and the page's JavaScript
  2. InfiniFrame.Js: Blazor-specific utilities for pointer capture and built-in window management message handlers

For executing arbitrary JavaScript from C# (as opposed to messaging), see the JavaScript Execution feature. For an overview of the feature system, see Window Features Architecture.

Contents​

Web Messaging​

The messaging channel works the same way regardless of whether you are using plain HTML, a Blazor app, or an ASP.NET Core server. Use this JavaScript API as the primary send path:

window.infiniframe.host.postData({ id: "my:event", command: "Post", data: { value: 1 }, version: 2 });

Messages are validated against a versioned envelope contract:

{ "id": "<string>", "command": "Post|Get", "data": null, "version": 2, "requestId": "<optional-string>", "channel": "<optional-string>" }

id, command, and version are required. version must be 2.

Legacy id;payload messaging is out of support. The JSON envelope contract is the only supported protocol.

Sending from C# to JavaScript​

window.SendWebMessage("hello from C#");
await window.SendWebMessageAsync("async hello");

In the browser:

window.infiniframe.host.receiveCallback(function(message) {
console.log("Received from C#:", message);
});

Sending from JavaScript to C#​

window.infiniframe.host.postData({ id: "action", command: "Post", data: 42, version: 2 });

In C#:

builder.Events.WebMessageReceived.Add(raw => {
var msg = JsonSerializer.Deserialize<MyMessage>(raw);
// handle msg
});

Named message handlers​

Instead of parsing all messages in one handler, register named handlers through IInfiniFrameWindowMessageHandlers:

// At build time, via the builder
var window = InfiniFrameWindowBuilder.Create()
...
.Build();

window.MessageHandlers.RegisterMessageHandler("ping", (window, _) => {
window.SendWebMessage("pong");
});

window.MessageHandlers.RegisterMessageHandler("set-title", (window, title) => {
// handle title change; title is the parsed envelope data
});
window.infiniframe.host.postData({ id: "ping", command: "Post", data: null, version: 2 });
window.infiniframe.host.postData({ id: "set-title", command: "Post", data: "New Title", version: 2 });

InfiniFrame.Js​

InfiniLore.InfiniFrame.Js provides Blazor-specific interop and registers built-in message handlers for window management from JavaScript.

Installation​

dotnet add package InfiniLore.InfiniFrame.Js

This package is automatically included by InfiniLore.InfiniFrame.BlazorWebView.

DI Registration​

When using the core package directly (not BlazorWebView), register the service manually:

services.AddInfiniFrameJs();

IInfiniFrameJs​

IInfiniFrameJs exposes pointer capture methods for Blazor components:

public interface IInfiniFrameJs {
Task SetPointerCaptureAsync(ElementReference element, long pointerId, CancellationToken ct);
Task ReleasePointerCaptureAsync(ElementReference element, long pointerId, CancellationToken ct);
}

These wrap the browser's element.setPointerCapture(pointerId) / element.releasePointerCapture(pointerId) APIs, which are necessary for reliable drag interactions. The pointer capture keeps events flowing to the element even after the pointer leaves it.

@inject IInfiniFrameJs InfiniJs

<div @ref="handle"
@onpointerdown="StartDrag"
@onpointerup="EndDrag">
Drag me
</div>

@code {
ElementReference handle;

async Task StartDrag(PointerEventArgs e) {
await InfiniJs.SetPointerCaptureAsync(handle, e.PointerId, default);
}

async Task EndDrag(PointerEventArgs e) {
await InfiniJs.ReleasePointerCaptureAsync(handle, e.PointerId, default);
}
}

Built-in JavaScript Message Handlers​

InfiniFrame.Js registers several message handlers that the client-side InfiniFrame.js script uses to control the native window from JavaScript.

Including the script​

<script src="_content/InfiniLore.InfiniFrame.Js/InfiniFrame.js"></script>

Available handlers​

Handler IDTriggered byWhat it does
__infiniframe:window:minimizeInfiniFrame.jsMinimize the window
__infiniframe:window:maximizeInfiniFrame.jsMaximize the window
__infiniframe:window:closeInfiniFrame.jsClose the window
__infiniframe:fullscreen:enterInfiniFrame.jsEnter fullscreen
__infiniframe:fullscreen:exitInfiniFrame.jsExit fullscreen
__infiniframe:title:changeInfiniFrame.jsUpdate the native window title
__infiniframe:open:externalInfiniFrame.jsOpen links with target="_blank" in the default browser

These are used internally by InfiniFrameWindowDragArea, InfiniFrameWindowButton, and related components. You do not need to call them manually unless you are building custom components.

Sending a window management message from custom JavaScript​

All messages follow a versioned JSON envelope:

window.infiniframe.host.postData({ id: "__infiniframe:window:minimize", command: "Post", data: null, version: 2 });
window.infiniframe.host.postData({ id: "__infiniframe:window:maximize", command: "Post", data: null, version: 2 });
window.infiniframe.host.postData({ id: "__infiniframe:window:close", command: "Post", data: null, version: 2 });
// Title data is the new title string
window.infiniframe.host.postData({ id: "__infiniframe:title:change", command: "Post", data: "New Window Title", version: 2 });
window.infiniframe.host.postData({ id: "__infiniframe:fullscreen:enter", command: "Post", data: null, version: 2 });
window.infiniframe.host.postData({ id: "__infiniframe:fullscreen:exit", command: "Post", data: null, version: 2 });

When using InfiniFrame.js, you can go through its API instead:

window.infiniframe.messaging.sendMessageToHost("__infiniframe:window:minimize");
window.infiniframe.messaging.sendMessageToHost("__infiniframe:title:change", "New Title");

Exchanging Structured Data​

The message channel uses a JSON envelope, so structured data can be placed directly in data.

C# to JS:

window.SendWebMessage(JsonSerializer.Serialize(new {
id = "update",
command = "Post",
data = new { count = 42 },
version = 2
}));
window.infiniframe.host.receiveCallback(function(raw) {
const envelope = JSON.parse(raw);
if (envelope.id === "update") {
updateUI(envelope.data.count);
}
});

JS to C#:

window.infiniframe.host.postData({
id: "log",
command: "Post",
data: { message: "hello" },
version: 2
});
window.MessageHandlers.RegisterMessageHandler("log", (_, payload) => {
using var doc = JsonDocument.Parse(payload!);
string? message = doc.RootElement.GetProperty("message").GetString();
Console.WriteLine(message);
});

Examples​

  • InfiniFrameExample.WebApp.Vue (examples/InfiniFrameExample.WebApp.Vue) - registers all built-in message handlers for window management, fullscreen, title change, and external links
  • InfiniFrameExample.WebApp.React (examples/InfiniFrameExample.WebApp.React) - custom scheme handler returning dynamic JavaScript, and a two-way messaging round-trip

See Also​