RxJs + ResizeObserver = ResizeObservable
The
ResizeObserverinterface reports changes to the dimensions of anElement‘s content or border box, or the bounding box of anSVGElement.

ResizeObserver comes in handy when you need to redraw, reorganize, restructure the view based on an element’s dimensions in it. Most cases are be handled by CSS obviously, or programatically the Window resize event, but sometimes only one element changes not the window size, for instance when we show/hide an element base on some condition that affects the others shown. In such cases ResizeObserver offers a great API to solve the issue. What’s greater though is having the same functionality, but with Observables. ResizeObserver works with a rather overcomplicated object structure for common use-case perspective, and also, with callbacks.
Solution 1:
Use a library.
This is a fair solution, although has the usual shortcomings of 3rd-party libraries.
Hasn’t been updated for years
console log left in there 😆
creates a new ResizeObserver for each subscriber for the same Element
uses debounceTime which delays emitting until the given time has passed without a new event, making a resize glitchy. Imagine the user resizing the window. As long as the size is changing, the subscribers won’t get a resize notification. Of course if the debounce time is low it won’t necessarily cause noticeable glitches, but still.
Actual solution
We don’t need to reinvent the wheel, but also including 3rd-parties for every is-odd calculation is a questionable decision. The best solution in my opinion is to create an instance of this Observable-Facade pattern that suites best your use-case.
Here’s an implementation to base this off of.
import { filter, map, NextObserver, Observable, Subscriber, throttleTime } from “rxjs”;
export class ResizeObservableService {
private resizeObserver: ResizeObserver;
private notifiers: NextObserver<ResizeObserverEntry[]>[] = [];
constructor() {
this.resizeObserver = new ResizeObserver((entries: ResizeObserverEntry[]) => {
this.notifiers.forEach(obs => obs.next(entries));
});
}
resizeObservable(elem: Element): Observable<ResizeObserverEntry> {
this.resizeObserver.observe(elem);
const newObserverCandidate = new Observable<ResizeObserverEntry[]>(
(subscriber: Subscriber<ResizeObserverEntry[]>) => {
this.notifiers.push(subscriber);
return () => {
const idx = this.notifiers.findIndex(val => val === subscriber);
this.notifiers.splice(idx, 1);
this.resizeObserver.unobserve(elem);
};
}
);
return newObserverCandidate.pipe(
map(entries => entries.find(entry => entry.target === elem)),
filter(Boolean),
throttleTime(30)
);
}
widthResizeObservable(elem: Element): Observable<number> {
return this.resizeObservable(elem).pipe(
map(entry => entry.borderBoxSize[0].inlineSize),
filter(Boolean)
);
}
}ResizeObserver is singleton for the class, no redundant instances are created.
ThrottleTime is used, so on continuous resize the event firing is guaranteed. I added a default value, but we could also include a config object if needed.
Usage is more than simple, subscribe on widthResizeObservable and you’ll receive the element’s size changes.
The code with an example usage can be found GitHub. It’s not published on npm 😝


