---
title: useThrottle composable
related:
  - title: useDebounce composable
    path: use-debounce.md
  - title: useTimeout composable
    path: use-timeout.md
  - title: Other Utils
    path: ../quasar-utils/other-utils.md
---
The `useThrottle()` composable is the [throttle](../quasar-utils/other-utils.md#throttle) util made aware of your component: it returns the very same throttled Function and drops the waiting call when the component gets destroyed or deactivated (keep-alive related).

Throttling runs your Function at most once every `limit` milliseconds while the calls keep coming: a scroll or mousemove handler that updates the UI, a progress report, a button that must not submit twice. The first call runs right away; the calls made during the following `limit` milliseconds are dropped, or, with `trailing` set to `true`, the last of them runs at the end of the window.

> [!NOTE]
> On the server-side of SSR or SSG modes, the returned Function does nothing.

> [!NOTE]
> The composable is for `setup()` only. Outside of a component (a boot file, a store, a plain module) use the [throttle](../quasar-utils/other-utils.md#throttle) util directly: it is the same Function, and nothing there gets destroyed that could drop a waiting call for you.

## Syntax

```js
import { useThrottle } from 'quasar'

setup () {
  // call it as you would call fn
  //   throttleFn.cancel() drops the waiting call and closes the window
  //   throttleFn.flush() runs the waiting call right away, as if the window had just ended
  const throttleFn = useThrottle(
    fn,
    100, // ms between two runs (default: 250)
    true // trailing: also run the last call made during a window at its end (default: false)
  )

  // ...
}
```

```ts
function useThrottle<F extends (...args: any[]) => any>(
  fn: F,
  limit?: number, // default: 250
  trailing?: boolean // default: false
): F & {
  cancel(): void
  flush(): void
}
```

The returned Function takes the same arguments as `fn`, forwards `this` to it and returns the result of the last run, so it can replace `fn` anywhere: an event handler, a watcher callback, an Options API method. Like the util's, it carries `cancel()` and `flush()`.

Without `trailing`, only the calls that find no window open run, so a burst of calls ends with the state of its first call. With `trailing` set to `true`, the last call made during a window runs at the end of it (with its own arguments), so the state of the last call always gets through; that run opens a window of its own. Leave `trailing` off when a late run would be harmful, like a submit handler.

`throttleFn.cancel()` drops the waiting call and closes the window, so that the next call runs right away. `throttleFn.flush()` runs the waiting call right away, as if the window had just ended: a fresh window opens from that moment, so the rate limit holds. Without a waiting call it does nothing.

## Example

Example "Pointer tracking":

```vue
<template>
  <div
    class="bg-grey-3 rounded-borders flex flex-center text-grey-8"
    style="height: 160px; user-select: none"
    @mousemove="onMove"
    @touchmove.prevent="onMove"
  >
    Move the pointer here
  </div>

  <div class="q-mt-md row justify-end">
    <q-badge color="grey-7" :label="`events: ${events}`" />
  </div>

  <q-markup-table flat bordered dense class="q-mt-sm">
    <thead>
      <tr>
        <th class="text-left">trailing</th>
        <th class="text-right">runs</th>
        <th class="text-right">position</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="tracker in trackers" :key="tracker.label">
        <td>
          <code>{{ tracker.label }}</code>
          <div class="text-caption text-grey-7">{{
            tracker.description
          }}</div>
        </td>
        <td class="text-right">{{ tracker.runs }}</td>
        <td class="text-right">{{ tracker.position }}</td>
      </tr>
    </tbody>
  </q-markup-table>
</template>

<script setup>
import { reactive, ref } from 'vue'
import { useThrottle } from 'quasar'

const events = ref(0)

function createTracker(label, description, trailing) {
  const tracker = reactive({ label, description, runs: 0, position: '-' })

  tracker.track = useThrottle(
    evt => {
      const point = evt.touches?.[0] ?? evt
      tracker.runs++
      tracker.position = `${Math.round(point.clientX)}, ${Math.round(point.clientY)}`
    },
    250,
    trailing
  )

  return tracker
}

const trackers = [
  createTracker(
    'false (default)',
    'Runs at most once every 250ms; a movement ends with an earlier position.'
  ),
  createTracker(
    'true',
    'Runs at most once every 250ms; the last position of a movement always gets through.',
    true
  )
]

function onMove(evt) {
  events.value++
  for (const tracker of trackers) {
    tracker.track(evt)
  }
}
</script>
```

Protecting a button against double submissions:

```js
import { useThrottle } from 'quasar'

setup () {
  // <q-btn label="Submit" @click="onSubmit" />
  const onSubmit = useThrottle(() => {
    // the calls made during the next second are dropped
  }, 1000)

  return { onSubmit }
}
```

> [!TIP]
> To run `fn` once the calls stop coming, rather than at a steady rate while they do, use [useDebounce](use-debounce.md) instead.
