Browser APIs
Rask reaches the browser's Web APIs two ways. Most are MDN's own surface, generated into C# by
Rask.Web: await Navigator.Clipboard.WriteText("hi"), await LocalStorage.GetItem("theme"). The
rest are typed C# wrappers — inject one through a component constructor and call it, instead of hand-writing
IJSRuntime identifiers and getting the JSON shape right yourself. Each is a thin, awaitable layer over the same unified
IJSRuntime, so it works the same way whether your
app runs on the Server (WebSocket) or WASM (JSImport/JSExport) transport.
This page is the map of the whole surface. For an at-a-glance view of where each API works
(Web / PWA), see the
capability matrix — it links to a dedicated reference page per API
under docs/apis/. For the deeper "why" — user activation, the transport seam, element
refs — see JS interop → Typed browser APIs; for the mobile/PWA
angle see the Mobile & PWA guide. Every wrapper has a runnable demo in the
showcase, under Browser APIs — except the WASM-only tier, which gets its own page under
PWA because it needs something the Server transport can't give it. (The activation-gated ones appear in both: as gesture components
under Browser APIs, and as injectable services or Rask.Web calls under PWA.)
Two homes, one rule
Rask.Core.Browser— APIs that work on every host (Server + WASM). Registered by both.Rask.Wasm.Browser— APIs only the WASM host can run: they need the installed-PWA instance, a live document, a device chooser, or transient user activation — preserved only when the interop call runs inside the click's own call stack, which the Server's WebSocket round-trip loses.
The rule: shared-everywhere APIs live in
Rask.Core.Browser, WASM-only ones inRask.Wasm.Browser. A host simply doesn't register a service it can't provide.
Sharing shows the split cleanly. The declarative, headless Shareable (Rask.Core) hands your markup
a data-rask-share attribute and the shared client fires navigator.share inside the click gesture — no
round-trip, so activation survives — so it works on every host, Server included. The imperative
await Navigator.Share(…) from Rask.Web shares from code (a lifecycle
hook, after an await), which only the WASM host can do, so it compiles only in a WASM app.
Call from an event handler or lifecycle hook, never from Render(). A typed wrapper is injected
through the constructor (not a settable property — that would become a required chain parameter):
public sealed partial class ThemeToggle : Component
{
protected override async Task OnFirstRender()
{
var saved = await LocalStorage.GetItem("theme"); // or: await Document.Cookie
var dark = saved is null
? await Window.MatchMedia("(prefers-color-scheme: dark)").Matches
: saved == "dark";
// …apply theme…
}
}
Browser-gated APIs (clipboard, geolocation, notifications, fullscreen, crypto's secure context, …)
can fail — a denial/timeout/unsupported surfaces as a JSException from the awaited task, so gate on
the API's IsSupported/permission check and wrap calls in try/catch.
See the capability matrix for which APIs work on which host.
On this page
- Web APIs from MDN — every web API the browser ships, generated from MDN into C# by
Rask.Web. - The sharing model — shared vs WASM-only wrappers, declarative vs imperative, the subscription push pattern.
- Reference & live demos — every wrapper with a runnable demo.
Notes
- Secure context. Clipboard, geolocation, notifications, push,
crypto.subtle, and others require HTTPS orlocalhost. - Permission/support gating. Many APIs expose
IsSupported(); askNavigator.Permissions.Query(…)fromRask.Webbefore triggering a prompt, andtry/catchthe call. - Trimming (WASM). Types these APIs deserialize are registered in source-gen JSON contexts, and the
push APIs'
[JSInvokable]methods are[DynamicDependency]-rooted, so everything stays correct in aPublishTrimmedapp.
See also: JS interop · Mobile & PWA.