---
title: v-resize directive
related:
  - title: Resize Observer
    path: ../vue-components/resize-observer.md
  - title: useElementSize composable
    path: ../vue-composables/use-element-size.md
  - title: v-mutation directive
    path: mutation.md
---
"Resize" is a Quasar directive that calls a method whenever the DOM element (or component) that it is applied to changes its size (width and/or height). The reported size is the element's outer size (padding and border included), so a padding change on the element itself is reported too.

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 template-side form of the [QResizeObserver](../vue-components/resize-observer.md) component and of the [useElementSize](../vue-composables/use-element-size.md) composable (both the component and the directive are built on it): unlike the component, it needs no extra node in your template and it can go on any element, including a component whose slot you would rather not touch.

## Resize API

### Directive Value

- `value` (Function | false, optional)
  Function to call right away with the initial size, then whenever the outer size (padding and border included) of the element changes; false or null (or undefined) disables the directive (the observer is dropped and recreated when a handler is supplied again)
  Function signature: `(size?: object) => false | void`
  Examples: `v-resize="myHandler"`, `v-resize="isEnabled ? myHandler : false"`
  Params:
    - `size` (object, optional)
      New size
      Object shape:
        - `height` (number, required)
          Layout height
        - `width` (number, required)
          Layout width
  Returns: `false | void`
    If you return Boolean false from the handler, the observer stops

### Directive Argument

- `arg` (number, optional), default `0`
  Debounce in milliseconds; the element is measured at most once per window, so the last change is never missed; 0 (the default) measures on every change
  Examples: `v-resize:100`, `v-resize:[debounce]`

### Directive Modifiers

- `once` (boolean, optional)
  Call handler only once, with the initial size, then stop observing
  Examples: `v-resize.once`

## Usage

The directive's value is the handler Function. It takes one parameter, an Object with the `width` and `height` of the element (in pixels). It gets called right away with the initial size, so you can rely on having it as soon as the element is rendered, then only when the size changes.

### Basic

```vue
<template>
  <q-btn
    color="primary"
    push
    @click="setRandomSize"
    label="Set Random Size"
  />

  <div
    v-resize="onResize"
    :style="style"
    class="container bg-amber rounded-borders glossy q-my-md"
  />

  <div v-if="report" class="q-gutter-sm row items-center">
    <div>Reported:</div>
    <q-badge :label="`width: ${report.width}`" />
    <q-badge :label="`height: ${report.height}`" />
  </div>
</template>

<script setup>
import { ref } from 'vue'

const style = ref({ width: '200px', height: '200px' })
const report = ref(null)

function onResize(size) {
  report.value = size
  // {
  //   width: 20 // width of container (in px)
  //   height: 50 // height of container (in px)
  // }
}

function setRandomSize() {
  style.value = {
    width: Math.floor(100 + Math.random() * 200) + 'px',
    height: Math.floor(100 + Math.random() * 200) + 'px'
  }
}
</script>

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

### Debouncing

The directive's argument is a debounce in milliseconds (ex: `v-resize:100`). With it, the element gets measured at most once per window of that many milliseconds: a continuous resize (dragging a handle, animating a width) reports periodically rather than on every frame, and the last change is never missed. Should the debounce need to change at runtime, use a dynamic argument (`v-resize:[debounce]`).

Example "Debounce":

```vue
<template>
  <div class="q-mb-md">
    Drag the bottom-right corner of the box. The box reports every frame, the
    debounced one at most every 300ms.
  </div>

  <div class="row q-col-gutter-md">
    <div class="col-6">
      <div
        v-resize="onImmediate"
        class="container bg-amber rounded-borders q-pa-sm"
      >
        Immediate: {{ immediate }}
      </div>
      <div class="q-mt-sm">Reports: {{ immediateCount }}</div>
    </div>

    <div class="col-6">
      <div
        v-resize:300="onDebounced"
        class="container bg-orange rounded-borders q-pa-sm"
      >
        Debounced: {{ debounced }}
      </div>
      <div class="q-mt-sm">Reports: {{ debouncedCount }}</div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const immediate = ref('')
const immediateCount = ref(0)
const debounced = ref('')
const debouncedCount = ref(0)

function onImmediate({ width, height }) {
  immediate.value = `${width} x ${height}`
  immediateCount.value++
}

function onDebounced({ width, height }) {
  debounced.value = `${width} x ${height}`
  debouncedCount.value++
}
</script>

<style lang="sass" scoped>
.container
  width: 100%
  height: 120px
  min-width: 100px
  min-height: 60px
  resize: both
  overflow: auto
</style>
```

### Trigger once

The directive can be used with the `once` modifier (ex: `v-resize.once`). The handler Function is called with the initial size of the element and the observing stops right there, which makes it a cheap way of reading an element's rendered size without a template ref.

### Disable

Passing in `false` or `null` (or `undefined`) instead of a Function disables the directive: the element stops being observed until a handler is supplied again, at which point the current size is reported if it changed meanwhile. The DOM element is untouched in the process, so whatever it wraps keeps its state.

```vue
<template>
  <div class="row no-wrap items-center q-gutter-md">
    <q-btn
      color="primary"
      push
      @click="setRandomSize"
      label="Set Random Size"
    />
    <q-toggle v-model="enabled" label="Observe" dense />
  </div>

  <div
    v-resize="enabled ? onResize : false"
    :style="style"
    class="container bg-amber rounded-borders glossy q-my-md"
  />

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

<script setup>
import { ref } from 'vue'

const enabled = ref(true)
const style = ref({ width: '200px', height: '200px' })
const report = ref(null)
const count = ref(0)

function onResize(size) {
  report.value = size
  count.value++
}

function setRandomSize() {
  style.value = {
    width: Math.floor(100 + Math.random() * 200) + 'px',
    height: Math.floor(100 + Math.random() * 200) + 'px'
  }
}
</script>

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