blog.itcode.devblog.itcode.dev

[Deep Dive into the Observer API] 3. ResizeObserver

The ResizeObserver API is an observer specialized for handling changes to the size of DOM elements. Let's look at how to use this observer, and how to use it conveniently in React through a custom hook.

[Deep Dive into the Observer API] 3. ResizeObserver

The ResizeObserver API is an observer specialized for handling changes to the size of DOM elements. Let's look at how to use this observer, and how to use it conveniently in React through a custom hook.
RWB0104
@RWBwritten at 2024-06-19 16:14:40
Deep Dive into the Observer API

시리즈 모아보기

Deep Dive into the Observer API

1 / 4

ResizeObserver is an observer that detects changes in the size of an element. When an element's width or height changes, it can detect this and perform the desired action.

TYPESCRIPT

const ro = new ResizeObserver(callback);

ro.observe(tag, options);

Unlike IntersectionObserver from the previous chapter, options are not assigned in the API. Instead, options can be specified together when registering an element via the observe method.

You can pass options when registering an element to fine-tune the detailed settings. It has the ResizeObserverOptions type.

Specifies the type of the element.

  • content-box - The size of the content area as defined by CSS
  • border-box - The size of the entire box area as defined by CSS (including margin, padding, and border)
  • device-pixel-content-box - The size of the content area defined in device pixel units

ResizeObserver's callback method is an event method that runs whenever an element's size changes.

It is declared with the ResizeObserverCallback type, which can be expressed in code as follows.

TYPESCRIPT

const ro = new ResizeObserver((entries, observer) => {});

entries has the ResizeObserverEntry[] type. It returns the event information of the elements registered in ResizeObserverEntry as an array.

By registering multiple DOM elements in ResizeObserverEntry, you can apply the observer to multiple objects.

🖼️ Basic box

Each item below is explained based on the box shown above.

🖼️ border-box

There are several elements that make up the size of content in CSS.

Each is composed of border and padding in the layout, and the size is determined based on the internal content.

borderBoxSize provides the size of the box encompassing all of these elements. It is an array, and each item has blockSize and inlineSize.

  • blockSize - Height (height)
  • inlineSize - Width (width)

🖼️ content-box

Returns the size information of the pure content only, excluding the border and padding that make up the box layout in CSS.

Like borderBoxSize, it is an array, and each item's information is the same as well.

  • blockSize - Height (height)
  • inlineSize - Width (width)

Returns the size information of the content area in device pixel units.

Like borderBoxSize, it is an array, and each item's information is the same as well.

  • blockSize - Height (height)
  • inlineSize - Width (width)

🖼️ contentRect

An object that returns various size information about elements, some of which overlaps with information provided by other objects.

This object is a legacy property, supported for backward compatibility, and there is a possibility it may be deprecated at some point. (reference)

  • width - Width of the pure content area (same as contentBoxSize)
  • height - Height of the pure content area (same as contentBoxSize)
  • x - The x coordinate of the content, based on the box
  • y - The y coordinate of the content, based on the box
  • left - The position of the left edge of the content. Usually the same as x
  • top - The position of the top edge of the content. Usually the same as y
  • right - The position of the right edge of the content.
  • bottom - The position of the bottom edge of the content.

Returns the DOM object that triggered the ResizeObserver event.

Returns the ResizeObserver object. Through this, ResizeObserver can also be handled in a chained manner within the callback method.

Let's use ResizeObserver conveniently through a custom hook.

TYPESCRIPT

export function useResizeObserver(): void
{
  //
}

Define the useResizeObserver method as above.

To use useResizeObserver, the following three elements are needed.

  1. The target DOM
  2. A callback method
  3. Options

Let's define these three elements as parameters. For the first one, an HTMLElement is normally required, but this hook will be built to accept not only the HTMLElement type but also a string, so that a tag can be targeted using a selector like #id or .class.

TYPESCRIPT

import { useEffect } from "react";

export type UseResizeObserverCallback = (entry: ResizeObserverEntry) => void;

/**
 * Hook method for applying ResizeObserver
 *
 * @param {Element | string | null} ref: Element
 * @param {UseResizeObserverCallback} callback: Callback method
 * @param {ResizeObserverOptions} options: Options
 */
export function useResizeObserver(ref: Element | string | null, callback: UseResizeObserverCallback, options?: ResizeObserverOptions): void
{
	//
}

The parameters are as above. Next, declare ResizeObserver and assign the callback method.

TYPESCRIPT

import { useEffect } from "react";

export type UseResizeObserverCallback = (entry: ResizeObserverEntry) => void;

/**
 * Hook method for applying ResizeObserver
 *
 * @param {Element | string | null} ref: Element
 * @param {UseResizeObserverCallback} callback: Callback method
 * @param {ResizeObserverOptions} options: Options
 */
export function useResizeObserver(ref: Element | string | null, callback: UseResizeObserverCallback, options?: ResizeObserverOptions): void
{
	useEffect(() =>
	{
		const ro = new ResizeObserver((entries) =>
		{
			entries.forEach(callback);
		});
	}, [ ref, callback, options ]);
}

Initialize ResizeObserver and assign it to the ro variable.

Next, assign the DOM specified by ref.

ref branches according to three possible states, as follows.

  • If it is null -> skip it.
  • If it is a string -> select the tag with the document.querySelector method, then register that tag.
  • If it is an HTMLElement -> since it is already an Element, register it immediately.

This was implemented by checking whether ref is a string via the typeof ref === "string" expression.

You can register a tag through the ro.observe() method.

TYPESCRIPT

import { useEffect } from "react";

export type UseResizeObserverCallback = (entry: ResizeObserverEntry) => void;

/**
 * Hook method for applying ResizeObserver
 *
 * @param {Element | string | null} ref: Element
 * @param {UseResizeObserverCallback} callback: Callback method
 * @param {ResizeObserverOptions} options: Options
 */
export function useResizeObserver(ref: Element | string | null, callback: UseResizeObserverCallback, options?: ResizeObserverOptions): void
{
	useEffect(() =>
	{
		const ro = new ResizeObserver((entries) =>
		{
			entries.forEach(callback);
		});

		// If the DOM is valid
		if (ref)
		{
			// If ref is a string
			if (typeof ref === 'string')
			{
				const tag = document.querySelector(ref);

				// If the tag is valid
				if (tag)
				{
					ro.observe(tag, options);
				}
			}

			// If it is a DOM element
			else
			{
				ro.observe(ref, options);
			}
		}
	}, [ ref, callback, options ]);
}

Finally, add cleanup code so that ResizeObserver registrations don't stack up every time the component re-renders.

ResizeObserver can be removed via the ro.disconnect() method.

TYPESCRIPT

import { useEffect } from "react";

export type UseResizeObserverCallback = (entry: ResizeObserverEntry) => void;

/**
 * Hook method for applying ResizeObserver
 *
 * @param {Element | string | null} ref: Element
 * @param {UseResizeObserverCallback} callback: Callback method
 * @param {ResizeObserverOptions} options: Options
 */
export function useResizeObserver(ref: Element | string | null, callback: UseResizeObserverCallback, options?: ResizeObserverOptions): void
{
	useEffect(() =>
	{
		const ro = new ResizeObserver((entries) =>
		{
			entries.forEach(callback);
		});

		// If the DOM is valid
		if (ref)
		{
			// If ref is a string
			if (typeof ref === 'string')
			{
				const tag = document.querySelector(ref);

				// If the tag is valid
				if (tag)
				{
					ro.observe(tag, options);
				}
			}

			// If it is a DOM element
			else
			{
				ro.observe(ref, options);
			}
		}

		return () =>
		{
			ro.disconnect();
		};
	}, [ ref, callback, options ]);
}

The full code is as above.

A simple example has been implemented in CodeSandbox.

By making use of ResizeObserver like this, you can easily handle viewport-related aspects of the DOM.

This API can replace the resize event, allowing for a more efficient event implementation.

In the next chapter, let's cover MutationObserver.

# JavaScript# TypeScript# React# Observer API# ResizeObserver
ship
blog.itcode.dev

Notes from the π-th Alpaca

7.0.1
Developed by RWB since 2021.057th upgraded at 2026.08