loading

Window events

AddEventListener / SubscribeEvent / RemoveEventListener

Attach a handler to any DOM event raised on window. SubscribeEvent returns a ButilSubscription - an IAsyncDisposable handle that detaches the listener when disposed, which is the safest pattern for lambdas.

C#
@implements IAsyncDisposable
@inject Bit.Butil.Window window

@code {
    private ButilSubscription? subscription;

    private async Task Subscribe()
    {
        subscription = await window.SubscribeEvent<ButilKeyboardEventArgs>(
            ButilEvents.KeyDown,
            args => Console.WriteLine($"{args.Key} ({args.Code})"));
    }

    public async ValueTask DisposeAsync()
    {
        if (subscription is not null) await subscription.DisposeAsync();
    }
}
Live sample

While subscribed, press any key and watch the console below.

window events output
Results will appear here when you interact with the samples.

Before-unload and page lifecycle

AddBeforeUnload / RemoveBeforeUnload / SubscribeFreeze / SubscribeResume

AddBeforeUnload makes the browser show a confirmation prompt before the user leaves or reloads the page - ideal for unsaved-changes protection. SubscribeFreeze and SubscribeResume observe the back/forward-cache lifecycle so you can release and re-acquire expensive resources.

C#
await window.AddBeforeUnload("You have unsaved changes.");

// later, when the data is saved:
await window.RemoveBeforeUnload();

var freezeSub = await window.SubscribeFreeze(() => { /* release resources */ });
var resumeSub = await window.SubscribeResume(() => { /* re-acquire them */ });
Live sample

Enable it, then try reloading this tab - the browser asks for confirmation.

page lifecycle output
Results will appear here when you interact with the samples.

Native dialogs

Alert / Confirm / Prompt

The classic blocking browser dialogs. Confirm resolves to a bool and Prompt resolves to the entered text, or null when the user cancels.

C#
await window.Alert("Hello from C#!");

bool ok = await window.Confirm("Proceed with the operation?");

string? name = await window.Prompt("What is your name?", "Butil");
Live sample
native dialogs output
Results will appear here when you interact with the samples.

Dimensions and offsets

GetInnerWidth / GetInnerHeight / GetOuterWidth / GetOuterHeight / GetScreenX / GetScreenY / GetScrollX / GetScrollY

Read the viewport and window sizes, the window position on the screen, and how far the document has been scrolled.

C#
var innerWidth = await window.GetInnerWidth();
var innerHeight = await window.GetInnerHeight();
var outerWidth = await window.GetOuterWidth();
var outerHeight = await window.GetOuterHeight();
var screenX = await window.GetScreenX();
var screenY = await window.GetScreenY();
var scrollX = await window.GetScrollX();
var scrollY = await window.GetScrollY();
Live sample
dimensions output
Results will appear here when you interact with the samples.

Scrolling

Scroll / ScrollBy

Scroll to an absolute position or by a relative offset. The ScrollOptions overloads add smooth or instant behavior control.

C#
await window.Scroll(0, 0);

await window.ScrollBy(0, 400);

await window.Scroll(new ScrollOptions
{
    Top = 0,
    Behavior = ScrollBehavior.Smooth,
});
Live sample
scrolling output
Results will appear here when you interact with the samples.

Popups, focus and printing

Open / Close / Focus / Blur / Print / Stop

Open returns an opaque tracking id you can later pass to Close to close that popup, or null when the browser blocked it. Print opens the print dialog for the current document, and Stop aborts any in-flight page loading.

C#
var popupId = await window.Open("https://bitplatform.dev", "_blank", new WindowFeatures
{
    Popup = true,
    Width = 600,
    Height = 400,
    NoOpener = true,
});

if (popupId is not null)
{
    await window.Close(popupId);
}

await window.Print();
Live sample
popups and printing output
Results will appear here when you interact with the samples.

Base64 helpers

Btoa / Atob

Btoa produces a base64-encoded ASCII string from binary string data and Atob decodes it back - the same semantics as the browser globals of the same names.

C#
var encoded = await window.Btoa("Hello Butil!");   // "SGVsbG8gQnV0aWwh"

var decoded = await window.Atob(encoded);          // "Hello Butil!"
Live sample
Text to encode
Base64 to decode
base64 output
Results will appear here when you interact with the samples.

Find and text selection

Find / GetSelection / GetSelectionText / SelectElement / CopySelection / ClearSelection

Find searches (and selects) text on the page. The selection helpers read the current selection as a snapshot, programmatically select an element's content, copy the selection to the clipboard, or clear it.

C#
bool found = await window.Find("butil", caseSensitive: false, wrapAround: true);

WindowSelection? selection = await window.GetSelection();
string text = await window.GetSelectionText();

await window.SelectElement(myElementReference);
bool copied = await window.CopySelection();
await window.ClearSelection();
Live sample
Search text
Selectable input (used by SelectElement)

Highlight any text on this page, then use the selection buttons.

find and selection output
Results will appear here when you interact with the samples.

Selection across shadow boundaries

IsComposedRangesSupported / GetComposedRanges

An ordinary selection can only describe boundaries in the document tree: one that starts or ends inside a shadow root is reported against the host element instead, which loses exactly what a component library needs to know. GetComposedRanges reports the real boundary points - but only inside the shadow roots you name, so encapsulation is kept. The boundary nodes themselves can't cross interop, so what identifies them is reported instead.

C#
var ranges = await window.GetComposedRanges(_componentHost);

foreach (var range in ranges)
{
    if (range.CrossesShadowBoundary) HandleInternalSelection(range);
}
Live sample

Select some text on this page first. With no shadow hosts passed, this reports the same boundaries an ordinary selection would - which is the point: a root you don't name stays hidden.

composed ranges output
Results will appear here when you interact with the samples.

Context, naming and media queries

IsSecureContext / GetOrigin / GetName / SetName / GetLocationBar / MatchMedia / WatchMatchMedia

Inspect the browsing context: secure-context state, origin, the window name and the location bar visibility. MatchMedia evaluates a CSS media query once, while WatchMatchMedia keeps a handler subscribed to its change event via a disposable subscription.

C#
bool secure = await window.IsSecureContext();
string origin = await window.GetOrigin();
BarProp locationBar = await window.GetLocationBar();

await window.SetName("butil-demo");
string name = await window.GetName();

MediaQueryList result = await window.MatchMedia("(max-width: 600px)");

ButilSubscription sub = await window.WatchMatchMedia(
    "(prefers-color-scheme: dark)",
    mql => Console.WriteLine($"dark mode: {mql.Matches}"));

// later: await sub.DisposeAsync();
Live sample
Window name
Media query

Watch the query, then resize the browser window to see change notifications.

context and media queries output
Results will appear here when you interact with the samples.
Warning:
Popup blockers Browsers only allow Open in response to a user gesture, and popup blockers can still veto it - always check the returned id for null before assuming the window exists.
Note:
Removing listeners added with lambdasRemoveEventListener matches by delegate identity, so a freshly created lambda never matches the registered one. Keep the original delegate in a field, or prefer SubscribeEvent and dispose the returned ButilSubscription.

API reference

Member
Signature
Description
AddEventListener
Task AddEventListener<T>(string domEvent, Action<T> listener, bool useCapture = false)
Attaches a handler to a DOM event on window.
RemoveEventListener
Task RemoveEventListener<T>(string domEvent, Action<T> listener, bool useCapture = false)
Detaches a previously added handler (matched by delegate identity).
SubscribeEvent
Task<ButilSubscription> SubscribeEvent<T>(string domEvent, Action<T> listener, bool useCapture = false)
AddEventListener variant returning a disposable subscription. An overload accepts ButilEventListenerOptions (capture, passive, once).
AddBeforeUnload
Task AddBeforeUnload()
Enables the browser's leave-confirmation prompt. An overload accepts a message string for maximum cross-browser consistency.
RemoveBeforeUnload
Task RemoveBeforeUnload()
Removes the beforeunload handlers registered by this instance.
SubscribeFreeze
Task<ButilSubscription> SubscribeFreeze(Action handler)
Fires when the page is frozen (moved to the back/forward cache).
SubscribeResume
Task<ButilSubscription> SubscribeResume(Action handler)
Fires when the page resumes from the back/forward cache.
GetInnerWidth / GetInnerHeight
Task<float> GetInnerWidth() / Task<float> GetInnerHeight()
The content-area (viewport) size in px, including rendered scrollbars.
GetOuterWidth / GetOuterHeight
Task<float> GetOuterWidth() / Task<float> GetOuterHeight()
The size of the whole browser window in px.
GetScreenX / GetScreenY
Task<float> GetScreenX() / Task<float> GetScreenY()
Distance from the browser viewport to the left/top edge of the screen.
GetScrollX / GetScrollY
Task<float> GetScrollX() / Task<float> GetScrollY()
How far the document has been scrolled horizontally/vertically.
IsSecureContext
Task<bool> IsSecureContext()
Whether the current context is secure (https or localhost).
GetOrigin
Task<string> GetOrigin()
The global object's origin, serialized as a string.
GetLocationBar
Task<BarProp> GetLocationBar()
The locationbar object; Visible is false when this window is a popup.
GetName / SetName
Task<string> GetName() / Task SetName(string value)
Reads or writes the name of the window.
Alert
Task Alert(string? message = null)
Displays a native alert dialog.
Confirm
Task<bool> Confirm(string? message = null)
Displays a confirmation dialog; resolves to the user's choice.
Prompt
Task<string?> Prompt(string? message, string? defaultValue)
Displays a text-input dialog; resolves to the entered text or null on cancel.
Btoa
Task<string> Btoa(string data)
Creates a base64-encoded ASCII string from a string of binary data.
Atob
Task<string> Atob(string data)
Decodes a base64-encoded string.
Find
Task<bool> Find(string? text = null, bool? caseSensitive = null, bool? backward = null, bool? wrapAround = null, bool? wholeWord = null, bool? searchInFrame = null)
Searches for a string in the window; true when a match is found.
GetSelection
Task<WindowSelection?> GetSelection()
Snapshot of the current selection (text plus range metadata).
GetSelectionText
Task<string> GetSelectionText()
Just the selected text.
SelectElement
Task SelectElement(Microsoft.AspNetCore.Components.ElementReference element)
Selects every text node inside the element (falls back to input select()).
CopySelection
Task<bool> CopySelection()
Copies the current selection to the clipboard; true on success.
ClearSelection
Task ClearSelection()
Removes any current selection.
IsComposedRangesSupported
Task<bool> IsComposedRangesSupported()
True when the runtime implements Selection.getComposedRanges().
GetComposedRanges
Task<ComposedRange[]> GetComposedRanges(params ElementReference[] shadowHosts)
The selection's ranges with boundary points inside the named shadow roots reported rather than collapsed onto the host. A root not named stays hidden.
MatchMedia
Task<MediaQueryList> MatchMedia(string query)
Evaluates a media query once, returning Matches and the normalized Media text.
SubscribeMatchMedia
Task<Guid> SubscribeMatchMedia(string query, Action<MediaQueryList> handler)
Subscribes to the query's change event; returns an id for UnsubscribeMatchMedia.
WatchMatchMedia
Task<ButilSubscription> WatchMatchMedia(string query, Action<MediaQueryList> handler)
SubscribeMatchMedia variant returning a disposable subscription.
UnsubscribeMatchMedia
ValueTask UnsubscribeMatchMedia(Guid id)
Removes a match-media listener. An overload accepts the handler and returns the removed ids (ValueTask<Guid[]>).
Open
Task<string?> Open(string? url = null, string? target = null, WindowFeatures? windowFeatures = null)
Opens a new window; returns a tracking id for Close, or null when blocked. An overload accepts the features as a raw string.
Close
Task Close(string? id = null)
Closes the current window, or the popup identified by the given tracking id.
Focus / Blur
Task Focus() / Task Blur()
Sets focus on, or away from, the window.
Print
Task Print()
Opens the print dialog for the current document.
Stop
Task Stop()
Stops window loading.
Scroll
Task Scroll(float? x, float? y)
Scrolls the window to an absolute position. An overload accepts ScrollOptions for smooth/instant behavior.
ScrollBy
Task ScrollBy(float? x, float? y)
Scrolls the document by a relative amount. An overload accepts ScrollOptions.
DisposeAsync
ValueTask DisposeAsync()
Releases every listener, media-query watcher, popup ref and beforeunload handler this instance registered. InvokeMediaQueryChange is the public JSInvokable dispatch bridge and is not intended for app code.
GetDevicePixelRatio
Task<double> GetDevicePixelRatio()
CSS pixels per device pixel - 2 on a typical retina display, fractional at OS zoom levels. Changes when the user zooms or moves the window to another monitor, so read it when needed rather than caching it.
IsCrossOriginIsolated
Task<bool> IsCrossOriginIsolated()
True when the page is cross-origin isolated, which unlocks SharedArrayBuffer and unthrottled high-resolution timers. Requires COOP and COEP response headers; Blazor WebAssembly multithreading needs it.
IsInIframe
Task<bool> IsInIframe()
True when this document is running inside a frame. Stays legal across origins, and returns true if the check itself is blocked, since only a cross-origin embedding causes that. Pair with Location.GetAncestorOrigins to find out who.
GetFrameCount
Task<int> GetFrameCount()
Number of frames directly inside this window (window.length).
MoveTo / MoveBy
Task MoveTo(float x, float y) | Task MoveBy(float x, float y)
Moves the window. Silently ignored for a normal tab - browsers only honor this for a window the script itself opened, and never for one with multiple tabs.
ResizeTo / ResizeBy
Task ResizeTo(float width, float height) | Task ResizeBy(float width, float height)
Resizes the window. Subject to the same restrictions as MoveTo.
An unhandled error has occurred. Reload 🗙