Skip to content

useResizeObserver

Attach a ResizeObserver to an element ref. The observer is created when the ref resolves, disconnected when the ref changes or the component scope is disposed, and re-attached automatically when the ref points at a new element.

Demo

Drag the bottom-right corner to resize.

0 × 0 px

<script setup lang="ts">
    import { ref, useTemplateRef } from 'vue';
    import { useResizeObserver } from '@basmilius/common';

    const target = useTemplateRef<HTMLTextAreaElement>('target');
    const size = ref({width: 0, height: 0});

    useResizeObserver(target, entries => {
        for (const entry of entries) {
            size.value = {
                width: Math.round(entry.contentRect.width),
                height: Math.round(entry.contentRect.height)
            };
        }
    });
</script>

<template>
    <div class="demo">
        <p class="hint">Drag the bottom-right corner to resize.</p>
        <textarea ref="target" class="resizable">Resize me</textarea>
        <p class="readout">{{ size.width }} × {{ size.height }} px</p>
    </div>
</template>

<style scoped>
    .demo {
        padding: 24px;
        border: 1px solid var(--vp-c-border);
        border-radius: 12px;
        background: var(--vp-c-bg-soft);
    }

    .hint {
        margin: 0 0 12px;
        color: var(--vp-c-text-2);
        font-size: 14px;
    }

    .resizable {
        display: block;
        width: 220px;
        height: 110px;
        min-width: 120px;
        min-height: 70px;
        max-width: 100%;
        padding: 12px;
        border: 1px solid var(--vp-c-border);
        border-radius: 8px;
        background: var(--vp-c-bg);
        font-family: var(--vp-font-family-mono);
        font-size: 14px;
        color: var(--vp-c-text-1);
        resize: both;
    }

    .readout {
        margin: 16px 0 0;
        font-family: var(--vp-font-family-mono);
        font-size: 18px;
        font-weight: 600;
        color: var(--vp-c-brand-1);
    }
</style>

Importing

ts
import { useResizeObserver } from '@basmilius/common';

Usage

vue
<script setup lang="ts">
    import { ref, useTemplateRef } from 'vue';
    import { useResizeObserver } from '@basmilius/common';

    const target = useTemplateRef<HTMLDivElement>('target');
    const size = ref({width: 0, height: 0});

    useResizeObserver(target, entries => {
        for (const entry of entries) {
            const rect = entry.contentRect;
            size.value = {
                width: rect.width,
                height: rect.height
            };
        }
    });
</script>

<template>
    <div ref="target" class="container">
        Size: {{ size.width }} x {{ size.height }}
    </div>
</template>

useTemplateRef('target') is Vue 3.5's preferred way to obtain a template ref — it binds to the element that has ref="target" and returns a ShallowRef so the observer reattaches automatically when the underlying element changes.

Pass ResizeObserverOptions (e.g. { box: 'border-box' }) when you need to opt into a different box model. Component refs are unwrapped via unwrapElement.

Type signature

ts
type EligibleElement = HTMLElement | ComponentPublicInstance;

declare function useResizeObserver<TElement extends EligibleElement>(
    elementRef: Ref<TElement | null>,
    callback: ResizeObserverCallback,
    options?: ResizeObserverOptions
): void;

See also