ResizeObserver

An API that lets you efficiently observe changes to the size of elements, replacing the unreliable window.resize event for element-level layout tracking.

Observers
Widely available (Chrome 64+, Firefox 69+, Safari 13.1+, Edge 79+)
Beginner
Impact: Low

When to Use

  • When you need to react to an individual element resizing (not the window).
  • When building components that adapt their layout to their container width (container queries).
  • When implementing charts, editors, or canvas elements that must rerender when their container changes size.
  • When replacing window.addEventListener("resize") for element-level tracking.

When NOT to Use

  • When you only need to track window/viewport size — use window.resize or the CSS `vw`/`vh` units instead.
  • When you need to react to CSS property changes other than size — use MutationObserver.
  • When polling the size once at mount time is sufficient — just read offsetWidth/offsetHeight directly.

Advantages vs Limitations

Advantages

  • Does not fire on every window resize — only when the observed element's content or border box actually changes.
  • More accurate than window.resize for element-level tracking.
  • Non-blocking: callbacks are invoked asynchronously, similar to IntersectionObserver.
  • Provides both contentRect and borderBoxSize, so you can choose what to measure.
  • Zero dependency on debouncing — the browser coalesces multiple resize events automatically.

Limitations

  • Callbacks fire asynchronously so there is one frame of delay before your component can react.
  • Does not observe CSS-only size changes (e.g. `display: none`) in all browsers consistently.
  • In older Safari versions, only contentRect is available (not borderBoxSize).
  • The observer must be explicitly disconnected on component unmount to avoid memory leaks.

Production Examples

Basic Vue usage with cleanup

Observe a single element for size changes. The observer is disconnected on unmount to prevent a memory leak.

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'

const containerRef = ref(null)
const containerWidth = ref(0)
let observer = null

onMounted(() => {
  observer = new ResizeObserver((entries) => {
    for (const entry of entries) {
      containerWidth.value = entry.contentRect.width
    }
  })
  observer.observe(containerRef.value)
})

onUnmounted(() => {
  observer?.disconnect()
})
</script>

<template>
  <div ref="containerRef">
    Container is {{ containerWidth }}px wide
  </div>
</template>

Using @vueuse/core useResizeObserver (recommended)

The VueUse useResizeObserver composable wraps the API and handles disconnection automatically when the component unmounts.

<script setup>
import { ref } from 'vue'
import { useResizeObserver } from '@vueuse/core'

const containerRef = ref(null)
const containerWidth = ref(0)

useResizeObserver(containerRef, (entries) => {
  containerWidth.value = entries[0].contentRect.width
})
// Cleanup is handled automatically by VueUse
</script>

Interview Readiness

Q: Why should you use ResizeObserver instead of window.addEventListener("resize") for element tracking?

A: window.resize fires for every viewport change regardless of whether a specific element changed size — and it fires on every pixel of window resize, requiring debouncing. ResizeObserver fires only when the observed element's actual size changes, is automatically coalesced by the browser, and works correctly when an element resizes due to content changes (not just window resize). It is also element-scoped, so you can observe any element in the DOM, not just the viewport.