Document
The DOM document loaded in the window: events, title and metadata, text direction, design mode, visibility, fullscreen and pointer lock - accessible from C# without any JavaScript.
@inject Bit.Butil.Document documentMDN reference
Attach a handler to any DOM event raised on document. The Document overloads additionally let you call preventDefault or stopPropagation on every occurrence, and SubscribeEvent returns a disposable ButilSubscription.
@implements IAsyncDisposable
@inject Bit.Butil.Document document
@code {
private ButilSubscription? subscription;
private async Task Subscribe()
{
subscription = await document.SubscribeEvent<ButilMouseEventArgs>(
ButilEvents.Click,
args => Console.WriteLine($"clicked at ({args.ClientX}, {args.ClientY})"));
}
public async ValueTask DisposeAsync()
{
if (subscription is not null) await subscription.DisposeAsync();
}
}While subscribed, click anywhere on the page and watch the coordinates below.
Read or change the document title shown in the browser tab, and inspect the document's URL and the page that linked to it.
string title = await document.GetTitle();
await document.SetTitle("New title from C#");
string url = await document.GetUrl();
string uri = await document.GetDocumentURI();
string referrer = await document.GetReferrer();Inspect how the browser parsed the document: its character encoding, MIME content type and whether it rendered in standards or quirks mode.
string charset = await document.GetCharacterSet(); // "UTF-8"
string contentType = await document.GetContentType(); // "text/html"
CompatMode compatMode = await document.GetCompatMode(); // CSS1Compat | BackCompatRead or flip the directionality of the whole document between left-to-right and right-to-left - handy for runtime language switching. Auto hands the choice to the browser, which takes it from the first strongly directional character in the content - the right setting when the language is not known up front.
DocumentDir dir = await document.GetDir();
await document.SetDir(DocumentDir.Rtl);
await document.SetDir(DocumentDir.Ltr);
await document.SetDir(DocumentDir.Auto);Design mode makes the entire document editable in place, the same switch developer tools use for quick copy tweaking.
DesignMode mode = await document.GetDesignMode();
await document.SetDesignMode(DesignMode.On);
await document.SetDesignMode(DesignMode.Off);While on, every piece of text on this page can be edited by clicking into it.
Visibility and focus
GetVisibilityState / IsHidden / HasFocus / WasDiscarded / SubscribeVisibilityChangeQuery whether the page is currently visible, hidden or focused, detect tabs restored after being discarded under memory pressure, and react to visibility flips - the standard trigger for pausing timers and media.
VisibilityState state = await document.GetVisibilityState();
bool hidden = await document.IsHidden();
bool focused = await document.HasFocus();
bool discarded = await document.WasDiscarded();
ButilSubscription sub = await document.SubscribeVisibilityChange(
state => Console.WriteLine($"visibility: {state}"));Subscribe, then switch to another tab and back to see the change events.
Exit the document's fullscreen element and observe fullscreen transitions. Entering fullscreen belongs to Butil's Element API (RequestFullScreen on an ElementReference); the document side handles the exit and the notifications.
ButilSubscription sub = await document.SubscribeFullscreenChange(
isFullscreen => Console.WriteLine($"fullscreen: {isFullscreen}"));
ButilSubscription errSub = await document.SubscribeFullscreenError(
() => Console.WriteLine("entering fullscreen failed"));
await document.ExitFullscreen();Pointer lock hides the cursor and streams raw movement deltas - the input model used by first-person games. The document side releases the lock and reports lock transitions and failures.
ButilSubscription sub = await document.SubscribePointerLockChange(
isLocked => Console.WriteLine($"pointer lock: {isLocked}"));
ButilSubscription errSub = await document.SubscribePointerLockError(
() => Console.WriteLine("acquiring pointer lock failed"));
await document.ExitPointerLock();Fires when the DOMContentLoaded event is raised - useful when bootstrapping post-render work after a circuit reconnect in Blazor Server.
ButilSubscription sub = await document.SubscribeDomContentLoaded(
() => Console.WriteLine("DOM is ready"));API reference
Task AddEventListener<T>(string domEvent, Action<T> listener, bool useCapture = false, bool preventDefault = false, bool stopPropagation = false)Task RemoveEventListener<T>(string domEvent, Action<T> listener, bool useCapture = false)Task<ButilSubscription> SubscribeEvent<T>(string domEvent, Action<T> listener, bool useCapture = false, bool preventDefault = false, bool stopPropagation = false)TimeSpan? MinInterval { get; set; }Task<string> GetCharacterSet()Task<CompatMode> GetCompatMode()Task<string> GetContentType()Task<string> GetDocumentURI()Task<DesignMode> GetDesignMode() / Task SetDesignMode(DesignMode mode)Task<DocumentDir> GetDir() / Task SetDir(DocumentDir dir)Task<string> GetReferrer()Task<string> GetTitle() / Task SetTitle(string title)Task<string> GetUrl()Task ExitFullscreen()Task ExitPointerLock()Task<VisibilityState> GetVisibilityState()Task<bool> IsHidden()Task<bool> HasFocus()ValueTask<bool> WasDiscarded()Task<ButilSubscription> SubscribeVisibilityChange(Action<VisibilityState> handler)Task<ButilSubscription> SubscribeFullscreenChange(Action<bool> handler)Task<ButilSubscription> SubscribeFullscreenError(Action handler)Task<ButilSubscription> SubscribePointerLockChange(Action<bool> handler)Task<ButilSubscription> SubscribePointerLockError(Action handler)Task<ButilSubscription> SubscribeDomContentLoaded(Action handler)ValueTask DisposeAsync()Task<string> GetReadyState()Task<string> GetLastModified()