@svelte-put/resize

GitHub Github

Svelte action wrapper for ResizeObserver

@svelte-put/resize @svelte-put/resize @svelte-put/resize @svelte-put/resize

Still on Svelte 4? See the old docs site here.

Prior Arts

Installation

npm install --save-dev @svelte-put/resize
pnpm add -D @svelte-put/resize
yarn add -D @svelte-put/resize

New to Svelte 5? See Migration Guides.

Quick Start

Use the resized CustomEvent (named so to avoid conflict with window's resize event) as the callback for ResizeObserver

<script lang="ts">
  import { resize, type ResizeDetail } from '@svelte-put/resize';

  function onResized(e: CustomEvent<ResizeDetail>) {
    const {
      observer, // see https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver
      entry, // see https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry
    } = e.detail;
  }
</script>

<div use:resize onresized={onResized} />

Example

This example is ported from MDN Docs, where border-radius will scale in proportion to the size of the box.

Example

Resize blue box (dragging bottom right corner) to see change

Expand the code block below to see how the example is implemented.

<script lang="ts">
	import { resize } from '@svelte-put/resize';
	import type { ResizeDetail } from '@svelte-put/resize';

	let enabled = $state(true);

	function calcBorderRadius(size1: number, size2: number) {
		return `${Math.min(100, size1 / 10 + size2 / 10)}px`;
	}

	function onResized(e: CustomEvent<ResizeDetail>) {
		const { entry } = e.detail;

		const target = entry.target as HTMLElement;
		if (entry.borderBoxSize?.length > 0) {
			target.style.borderRadius = calcBorderRadius(
				entry.borderBoxSize[0].inlineSize,
				entry.borderBoxSize[0].blockSize,
			);
		} else {
			target.style.borderRadius = calcBorderRadius(
				entry.contentRect.width,
				entry.contentRect.height,
			);
		}
	}

	let box: HTMLDivElement;
	$effect(() => {
		if (!enabled) box.style.borderRadius = '8px';
	});
</script>

<div class="flex flex-col items-center space-y-4">
	<p>
		Resize <span class="bg-blue-500 px-2 text-white">blue</span> box (dragging bottom right corner) to
		see change
	</p>
	<div
		class="h-24 w-24 resize overflow-auto bg-blue-500"
		use:resize={{ enabled }}
		onresized={onResized}
		bind:this={box}
	></div>
	<div class="flex items-center space-x-2">
		<label for="resize-enable">Check to {enabled ? 'disable' : 'enable'} action:</label>
		<input
			type="checkbox"
			id="resize-enable"
			bind:checked={enabled}
			class="c-input accent-primary h-5 w-5"
		/>
	</div>
</div>

Configuration

resize accepts a config object with the following interface.

/** config behavior of `resize` */
export interface ResizeConfig {
	/**
	 * whether to activate the action. Default to `true`
	 * @default true
	 */
	enabled?: boolean;
	/**
	 * Be default, a singleton ResizeObserver is used for all actions for
	 * better performance. You can use this option to create a new ResizeObserver
	 * or provide your own.
	 * @default 'singleton'
	 */
	observer?: 'singleton' | 'new' | ResizeObserver;

	/**
	 * Options passed to {@link https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/observe#options | ResizeObserver.observe}
	 * @default undefined
	 */
	options?: ResizeObserverOptions;
}

Browser Support & Polyfill

As of this writing, caniuse shows that ResizeObserver is supported by all major browsers, but not IE11. @svelte-put/resize tries to stay minimal and hence does not include a polyfill. If one is needed, consider resize-observer-polyfill.

Migration Guides

V3 -> V4 (Svelte 5 in Runes mode)

When migrating to V4, you will need to change event directive on:resized to standard attribute onresized:

<div use:resize on:resized></div>
<div use:resize onresized></div>

Happy resizing! 👨‍💻

Edit this page on Github