---
title: useElementSize composable
related:
  - title: Resize Observer
    path: ../vue-components/resize-observer.md
  - title: v-resize directive
    path: ../vue-directives/resize.md
---
The `useElementSize()` composable tracks the size of an element (or of a component) through a reactive `elementSize` Object holding its `width` and `height`. Under the hood it uses the [Resize Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Resize_Observer_API), so no polling is involved.

It is the setup-code counterpart of the [QResizeObserver](../vue-components/resize-observer.md) component and of the [v-resize](../vue-directives/resize.md) directive, which are both built on it. Use the composable when you want the size on your component or on any element or component ref, without adding an extra node to your template.

The reported size is the element's outer size (padding and border included), so a padding change on the element itself is reported too.

> [!NOTE]
> On the server-side of SSR or SSG modes, the composable never measures anything: `elementSize` stays at `{ width: 0, height: 0 }` until the client takes over.

> [!TIP]
> **Outside of a component**
>
> The composable can also be called outside of `setup()`: in a boot file, a store or a plain module. There is no component root to fall back on and no mount to wait for, so supply a `target` (an element, or a ref or getter of one); the observation starts right away and nothing stops it by itself: call `stopElementSize()` when you are done.

## Syntax

```js
import { useTemplateRef } from 'vue'
import { useElementSize } from 'quasar'

setup () {
  const target = useTemplateRef('target') // an Element or a component

  const { elementSize, refreshElementSize, stopElementSize } = useElementSize({
    // all optional:
    target,                  // (default: the component's own root element)
    debounce: 100,           // ms; at most one measurement per window (default: 0, one per change)
    disabled: true,          // pause observing (default: false)
    onResize (elementSize) { // called with { width, height } on every change
      // ...
    }
  })

  // ...
}
```

```ts
function useElementSize(
  options?: MaybeRefOrGetter<{
    target?: MaybeRefOrGetter<
      Element | ComponentPublicInstance | null | undefined
    >
    debounce?: string | number
    disabled?: boolean
    onResize?: (elementSize: { width: number; height: number }) => void
  }>
): {
  elementSize: ShallowRef<{ width: number; height: number }>
  refreshElementSize: () => void
  stopElementSize: () => void
}
```

Without a `target`, the composable measures the root element of the component it is called in, as of the moment the component gets mounted. A component rendering a fragment (multiple root nodes) has no root element to measure, so supply a `target` there.

The first measurement happens as soon as the element is available, so `elementSize` holds the size right after your component gets mounted; `onResize` is called for it as well, then only when the size changes. Each change assigns a new Object to `elementSize`, so a watcher on the ref fires once per reported size.

With a `debounce`, the element gets measured at most once per window of that many milliseconds: a continuous resize (dragging a splitter, animating a width) reports periodically rather than on every frame, and the last change is never missed.

`refreshElementSize()` measures the element right away, skipping the debounce (it does nothing while `disabled` or before the target exists). You will rarely need it, since the browser reports every change on its own.

`stopElementSize()` ends the observation for good. You will rarely need it either, as the composable stops by itself when the component gets destroyed.

## Changing the options while running

The options can be a plain Object, a Ref or a getter Function. A plain Object is read once. With a Ref or a getter, the composable tracks whatever reactive state the options read and re-applies them whenever that state changes, so you never call anything to "update" it:

- toggling `disabled` pauses and resumes the observation (`elementSize` keeps its last value while paused, and resuming measures right away)
- pointing `target` to another element (or letting a template ref change through `v-if`) follows it and reports the new element's size
- changing `debounce` applies from the next change
- swapping `onResize` takes effect from the next change

```js
import { ref } from 'vue'
import { useElementSize } from 'quasar'

setup () {
  const paused = ref(false)

  const { elementSize } = useElementSize(() => ({
    disabled: paused.value,
    debounce: paused.value ? 0 : 100
  }))

  function pause () { paused.value = true }
  function resume () { paused.value = false }

  // ...
}
```

## Example

The box below is measured through a template ref: `elementSize` follows it, and the `onResize` hook counts how many times the size got reported:

Example "Measuring an element":

```vue
<template>
  <q-btn
    color="primary"
    push
    label="Random height"
    @click="setRandomHeight"
  />

  <q-slider color="teal" v-model="boxWidth" :min="100" :max="300" label />

  <div
    ref="boxRef"
    :style="style"
    class="container bg-amber rounded-borders glossy q-my-md"
  />

  <div class="q-gutter-sm row items-center">
    <div>Measured:</div>
    <q-badge :label="`width: ${elementSize.width}`" />
    <q-badge :label="`height: ${elementSize.height}`" />
    <q-badge color="secondary" :label="`reports: ${reports}`" />
  </div>
</template>

<script setup>
import { computed, ref, useTemplateRef } from 'vue'
import { useElementSize } from 'quasar'

const boxRef = useTemplateRef('boxRef')

const boxWidth = ref(200)
const boxHeight = ref(120)
const reports = ref(0)

const style = computed(() => ({
  width: boxWidth.value + 'px',
  height: boxHeight.value + 'px'
}))

const { elementSize } = useElementSize({
  target: boxRef,
  onResize() {
    reports.value++
  }
})

function setRandomHeight() {
  boxHeight.value = Math.floor(80 + Math.random() * 120)
}
</script>

<style lang="sass" scoped>
.container
  transition: height .3s
</style>
```

To measure the component's own root element instead, omit the `target`:

```html
<template>
  <div class="chart">
    <svg
      :viewBox="`0 0 ${elementSize.width} ${elementSize.height}`"
      :width="elementSize.width"
      :height="elementSize.height"
    >
      <!-- ... -->
    </svg>
  </div>
</template>

<script setup>
  import { useElementSize } from 'quasar'

  // measures this component's root element (the chart container)
  const { elementSize } = useElementSize({ debounce: 100 })
</script>
```
