@svelte-put/resize
GithubCompatible with or powered directly by Svelte runes.
Prior Arts
- svelte-actions-resize: very minimal, no typescript support
- svelte-observer-resize: very similar to this implementation, but no typescript & ssr support
- svelte-resize-observer: component-based-strategy, including resize-observer-polyfill by default
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.
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! 👨💻