resize-observer
Observe size changes of one or more reactive elements.
| Package | @vizejs/composable/resize-observer |
| Own the source | vize lib pull composable:resize-observer |
| Runtime exports | useResizeObserver, useElementSize |
| Gzip budget | 2816 B |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/composable
Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.
import { useResizeObserver, useElementSize } from "@vizejs/composable/resize-observer";
Try it
Observe the size of a selected guide panel
Report the native content-box measurement of one panel and follow a changing target without observing the other panel.
What to observe: Toggle Wide first panel to change its real CSS size and delivered measurement. Resizing the second panel leaves the first panel's readout alone. Choose Second guide panel to retarget the observer. Stop size observation freezes the last delivered measurement while both native checkboxes keep resizing their panels.
A computed template target selects one actual section. The native callback reads contentRect and labels its target; its notification count counts deliveries, not every layout change. Border and padding are excluded from the reported content box. Retargeting disconnects the previous observer, and stop permanently stops its watcher and observer. A callback entry from an earlier target is ignored by this example. During SSR there is no host, support is false, and no measurement is taken. The browser host resolves after mounting, retaining the initial hydration markup. Scope disposal also disconnects observation. Panel classes and responsive maximum width remain ordinary CSS.
Compare the initial and interacted states


Copy the example
Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.
<script setup lang="ts">
import { computed, ref, useId, useTemplateRef } from "vue";
import { useResizeObserver } from "@vizejs/composable/resize-observer";
const panelsId = useId();
const first = useTemplateRef<HTMLElement>("first");
const second = useTemplateRef<HTMLElement>("second");
const firstWide = ref(true);
const secondWide = ref(false);
const selected = ref("first");
const target = computed(() => (selected.value === "first" ? first.value : second.value));
const observedWidth = ref(0);
const observedHeight = ref(0);
const observedName = ref("No panel observed yet");
const notifications = ref(0);
const stopped = ref(false);
const { isSupported, stop } = useResizeObserver(target, (entries) => {
const entry = entries.find((candidate) => candidate.target === target.value);
if (!entry) return;
observedWidth.value = entry.contentRect.width;
observedHeight.value = entry.contentRect.height;
observedName.value = entry.target === first.value ? "First guide panel" : "Second guide panel";
notifications.value += 1;
});
function stopObservation(): void {
stop();
stopped.value = true;
}
</script>
<template>
<div class="composable-example">
<label :for="`${panelsId}-target`">Observed guide panel</label>
<select :id="`${panelsId}-target`" v-model="selected">
<option value="first">First guide panel</option>
<option value="second">Second guide panel</option>
</select>
<div class="example-actions">
<label class="panel-size-choice"
><input v-model="firstWide" type="checkbox" /> Wide first panel</label
>
<label class="panel-size-choice"
><input v-model="secondWide" type="checkbox" /> Wide second panel</label
>
</div>
<div class="guide-panels">
<section
ref="first"
class="guide-panel"
:class="{ wide: firstWide }"
aria-label="First guide panel"
>
<strong>First guide panel</strong>
<p>Compile a representative component.</p>
</section>
<section
ref="second"
class="guide-panel"
:class="{ wide: secondWide }"
aria-label="Second guide panel"
>
<strong>Second guide panel</strong>
<p>Review native keyboard interaction.</p>
</section>
</div>
<output aria-live="polite">
Last observed: {{ observedName }} · Content box: {{ Math.round(observedWidth) }} ×
{{ Math.round(observedHeight) }} CSS pixels · Notifications: {{ notifications }}
</output>
<button type="button" :disabled="stopped || !isSupported" @click="stopObservation">
Stop size observation
</button>
<p v-if="stopped">
Observation stopped. Both panels can still resize; the last delivered measurement is retained.
</p>
<p v-else>
Only the selected panel updates the readout. Changing the selected target detaches the
previous observer.
</p>
<p v-if="!isSupported">Resize observation is not available in this context.</p>
</div>
</template>
<style scoped>
.panel-size-choice {
display: inline-flex;
align-items: center;
gap: 6px;
input {
inline-size: auto;
}
}
.guide-panels {
display: grid;
gap: 12px;
margin-block: 12px;
}
.guide-panel {
box-sizing: border-box;
inline-size: 180px;
max-inline-size: 100%;
padding: 12px;
border: 1px solid currentColor;
border-radius: 8px;
}
.guide-panel.wide {
inline-size: 280px;
}
</style>
Runtime contract
| Utility | Category | Stability | SSR | Hydration | Cleanup | Targets | Host globals | Uses |
|---|---|---|---|---|---|---|---|---|
useResizeObserver |
dom | experimental | deterministic-fallback | stable | caller, reactive-scope | web, desktop | globalThis, ResizeObserver |
resolveElements, tryOnScopeDispose |
useElementSize |
dom | experimental | deterministic-fallback | stable | caller, reactive-scope | web, desktop | globalThis, ResizeObserver |
useResizeObserver, resolveElement, tryOnScopeDispose |
API
useResizeObserver
Observe size changes of one or more reactive elements. A single observer is (re)created whenever the resolved targets, the box option, or the host change; unresolved targets are skipped. The observer is disconnected when the owning reactive scope stops or stop is called. During server rendering no host resolves, isSupported stays false, and the callback never runs. Inside a component the host is read after mounting, so hydration renders the server fallback first and never mismatches.
function useResizeObserver( targets: MaybeElementTargets, callback: ResizeObserverCallback, options: UseResizeObserverOptions = {}, ): ResizeObserverControls
useElementSize
Track the rendered size of a reactive element. Reads the requested box from contentBoxSize/borderBoxSize (summing fragments) and falls back to contentRect for older engines. When the target unmounts the size resets to the initial value so stale geometry never leaks into the next render. Server renders expose initialSize.
function useElementSize( target: MaybeElementTarget, options: UseElementSizeOptions = {}, ): ElementSizeControls
Types
ResizeObserverHost
Runtime capability that supplies the ResizeObserver constructor.
| Member | Type | Description |
|---|---|---|
ResizeObserver? |
new (callback: ResizeObserverCallback) => ResizeObserver |
ResizeObserver constructor, absent in unsupported runtimes. |
UseResizeObserverOptions
Options for useResizeObserver.
| Member | Type | Description |
|---|---|---|
box? |
ResizeObserverBoxOptions |
Box model reported by the observer. |
host? |
MaybeRefOrGetter<ResizeObserverHost | null | undefined> |
Reactive constructor capability for alternate runtimes and tests. |
flush? |
"pre" | "post" | "sync" |
Target resolution timing. "post" observes template refs after mount. |
ResizeObserverControls
Controls returned by useResizeObserver.
| Member | Type | Description |
|---|---|---|
isSupported |
Readonly<Ref<boolean>> |
Whether the host provides ResizeObserver. false during server rendering. |
stop |
() => void |
Disconnect the observer and stop following the reactive targets. Idempotent. |
ElementSize
Element dimensions reported by useElementSize.
| Member | Type | Description |
|---|---|---|
width |
number |
Inline size in CSS pixels. |
height |
number |
Block size in CSS pixels. |
UseElementSizeOptions
Options for useElementSize.
| Member | Type | Description |
|---|---|---|
box? |
ResizeObserverBoxOptions |
Box model reported by the observer. |
host? |
MaybeRefOrGetter<ResizeObserverHost | null | undefined> |
Reactive constructor capability for alternate runtimes and tests. |
flush? |
"pre" | "post" | "sync" |
Target resolution timing. "post" observes template refs after mount. |
initialSize? |
ElementSize |
Size exposed before the first observation and during server rendering. Keep it identical on server and client to avoid hydration mismatches. |
ElementSizeControls
Reactive size returned by useElementSize.
| Member | Type | Description |
|---|---|---|
isSupported |
Readonly<Ref<boolean>> |
Whether the host provides ResizeObserver. false during server rendering. |
stop |
() => void |
Disconnect the observer and stop following the reactive targets. Idempotent. |
width |
Readonly<Ref<number>> |
Observed inline size in CSS pixels. |
height |
Readonly<Ref<number>> |
Observed block size in CSS pixels. |