useResizeObserver
A composable for detecting element size changes using the Resize Observer API with automatic cleanup.
Usage
The useResizeObserver composable wraps the Resize Observer API to detect when an element’s dimensions change. It’s useful for responsive components, charts, virtualized lists, and aspect ratio maintenance.
Why wrap ResizeObserver? The native ResizeObserver has no awareness of Vue’s effectScope lifecycle. If you create one inside a composable, it won’t automatically disconnect when the scope is disposed. useResizeObserver integrates onScopeDispose for automatic cleanup, defers creation until after hydration for SSR safety, and adds reactive target tracking — things the native API can’t do on its own.
<script setup lang="ts">
import { useResizeObserver } from '@vuetify/v0'
import { ref, useTemplateRef } from 'vue'
const container = useTemplateRef('container')
const width = ref(0)
const height = ref(0)
useResizeObserver(container, (entries) => {
const entry = entries[0]
width.value = entry.contentRect.width
height.value = entry.contentRect.height
})
</script>
<template>
<div ref="container" class="resizable">
<p>Width: {{ width }}px</p>
<p>Height: {{ height }}px</p>
</div>
</template>Architecture
useResizeObserver wraps the native ResizeObserver API with Vue reactivity:
Options
| Option | Type | Default | Notes |
|---|---|---|---|
immediate | boolean | false | Fire the callback immediately on mount before any resize |
once | boolean | false | Stop observing after the first callback fires |
box | 'content-box' | 'border-box' | 'content-box' | Which box model a change is measured against when deciding to fire |
Entry
Each reported entry carries both box models, whichever box you observe:
| Property | Type | Notes |
|---|---|---|
contentRect | { width, height, top, left } | The content box — excludes padding and border |
contentBoxSize | readonly ResizeObserverSize[] | The content box on the logical axes (inlineSize / blockSize) |
borderBoxSize | readonly ResizeObserverSize[] | The border box — content plus padding plus border |
target | Element | The observed element |
Both size arrays mirror the native API: one entry per box fragment, so a normal single-fragment element is borderBoxSize[0].
useResizeObserver(el, ([entry]) => {
entry.contentRect.height // 30 — content box
entry.borderBoxSize[0].blockSize // 40 — with 4px padding and a 1px border
}, { box: 'border-box' })inlineSize vs widthinlineSize and blockSize follow the writing mode. Under the default horizontal-tb they map to width and height; under any vertical-* mode they swap. Unlike getBoundingClientRect(), neither is scaled by CSS transforms — which is what makes them the right choice for measuring an animated element.
Reactivity
| Property/Method | Reactive | Notes |
|---|---|---|
isActive | Computed from observer ref | |
isPaused | ShallowRef, readonly | |
target | Accepts MaybeRef, watched for changes | |
pause() | — | Temporarily stop observing without disconnecting |
resume() | — | Resume after pause() |
stop() | — | Disconnect the observer permanently |
useElementSize
| Property/Method | Reactive | Notes |
|---|---|---|
width | ShallowRef | |
height | ShallowRef |
Examples
Drag the right edge to resize. Columns: 1
FAQ
Use it for component (container) queries — when an element’s layout depends on its own measured width rather than the viewport. A media query only reacts to the global viewport, so the same component placed in a narrow column won’t adapt.
Call pause() to stop receiving callbacks and resume() to continue with the same observer. Use stop() only when you want to disconnect permanently.
Yes. useElementSize builds on useResizeObserver and exposes reactive width and height refs directly.
useResizeObserver reports an element’s size changes; useIntersectionObserver reports when it enters or leaves the viewport. Reach for resize when layout depends on measured dimensions, intersection when it depends on visibility.
Read entry.borderBoxSize[0] — it includes padding and border, where contentRect excludes them. Both are on every entry, so you can read the border box without changing any option.
box: 'border-box' is a separate choice: it controls which box model has to change before the observer fires. Set it when you only care about the outer size — an element whose padding grows while its border box stays fixed then won’t wake your callback.
borderBoxSize measures the same box but is a layout value, so CSS transforms don’t scale it. If the element is animated with transform, getBoundingClientRect() reports the visually scaled size while borderBoxSize reports the laid-out size — usually what sizing logic wants.