Back to APIs

ResizeObserver

Observers

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

SupportChrome 64+, Firefox 69+, Safari 13.1+, Edge 79+
BaselineWidely available
ImpactLow
Popularity🔥 70

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.

Code 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>

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.

Common Mistakes

  • Forgetting to call observer.disconnect() on component unmount — causes a memory leak.
  • Reading layout properties (offsetWidth) inside the callback without batching — can cause layout thrashing.
  • Observing too many elements simultaneously — prefer observing a common ancestor.
  • Using window.addEventListener("resize") as a fallback inside the callback — double-handling events.

References