loading

Observe size changes

ObserveResize

Capture the element with the ref directive and call ObserveResize with the IJSRuntime and a handler. The browser reports an initial entry immediately, then again on every size change. The box below has a CSS resize handle in its bottom-right corner - start observing, then drag it.

Razor
@inject IJSRuntime js

<div @ref="box" style="resize: both; overflow: auto;">Drag my corner</div>

@code {
    private ElementReference box;
    private ButilSubscription? subscription;

    private async Task Start()
    {
        subscription = await box.ObserveResize(js, entries =>
        {
            foreach (var entry in entries)
            {
                Console.WriteLine($"{entry.InlineSize} x {entry.BlockSize}");
            }
        });
    }
}
Live sample
Drag my bottom-right corner to resize me.
observe output
Results will appear here when you interact with the samples.

Box models

ResizeObserverBox

The box parameter selects which box dimensions trigger the observer: ContentBox (the default) excludes padding and borders, BorderBox includes them, and DevicePixelContentBox measures in physical device pixels - the choice that matters when sizing a canvas backing store. Pick one below and re-observe.

C#
await box.ObserveResize(js, entries =>
{
    // fires when the border box changes size
}, ResizeObserverBox.BorderBox);
Live sample
Observed box
box models output
Results will appear here when you interact with the samples.

Reading entries

ResizeObserverEntry

Each entry flattens the browser's ResizeObserverEntry into the fields layout work actually needs: the content rect, the logical inline and block sizes of the observed box, and the device-pixel sizes for pixel-perfect rendering.

C#
await box.ObserveResize(js, entries =>
{
    var entry = entries[^1];

    Rect? rect = entry.ContentRect;      // content box geometry
    var inline = entry.InlineSize;       // width in horizontal writing mode
    var block = entry.BlockSize;         // height in horizontal writing mode
    var dpInline = entry.DevicePixelInlineSize;
    var dpBlock = entry.DevicePixelBlockSize;
});
Live sample
entries output
Results will appear here when you interact with the samples.

Programmatic changes fire too

ObserveResize + SetAttribute

The observer does not care who changed the size: user drags, CSS state changes, Blazor re-renders and style writes all produce entries. Here the button widens the box through the Element extension SetAttribute while the observer reports each step.

C#
// any style write triggers the observer just like a user drag:
await box.SetAttribute("style", "width: 20rem; height: 6rem; resize: both; overflow: auto;");
Live sample
programmatic changes output
Results will appear here when you interact with the samples.

Stopping

ButilSubscription

ObserveResize returns a ButilSubscription; disposing it unobserves the element and releases the interop reference. Dispose every observer you start - at the latest in your component's DisposeAsync, as this page does.

Razor
@implements IAsyncDisposable

private ButilSubscription? subscription;

public async ValueTask DisposeAsync()
{
    if (subscription is not null)
    {
        await subscription.DisposeAsync();
    }
}
Live sample
stopping output
Results will appear here when you interact with the samples.
Note:
An initial entry arrives immediately Like the native API, observation starts with one report of the element's current size before any actual resize happens. That makes it safe to drive layout from the callback alone - you never need a separate initial measurement.

API reference

Member
Signature
Description
ObserveResize
Task<ButilSubscription> ObserveResize(IJSRuntime js, Action<ResizeObserverEntry[]> handler, ResizeObserverBox box = ResizeObserverBox.ContentBox)
Extension method on ElementReference. Starts observing size changes and returns a disposable subscription.
ResizeObserverBox
enum ResizeObserverBox { ContentBox, BorderBox, DevicePixelContentBox }
Selects which box dimensions trigger the observer.
ResizeObserverEntry.ContentRect
Rect? ContentRect { get; set; }
The content box geometry of the observed element.
ResizeObserverEntry.InlineSize
double InlineSize { get; set; }
Logical inline size of the observed box (width in horizontal writing modes).
ResizeObserverEntry.BlockSize
double BlockSize { get; set; }
Logical block size of the observed box (height in horizontal writing modes).
ResizeObserverEntry.DevicePixelInlineSize
double DevicePixelInlineSize { get; set; }
Inline size in physical device pixels.
ResizeObserverEntry.DevicePixelBlockSize
double DevicePixelBlockSize { get; set; }
Block size in physical device pixels.
ButilSubscription.Id
Guid Id { get; }
The internal listener id of the subscription.
ButilSubscription.DisposeAsync
ValueTask DisposeAsync()
Stops observing and releases the interop reference. Idempotent.
An unhandled error has occurred. Reload 🗙