use-simple-debounce Simple, dependency-free debouncing

import { useDebounce } from 'use-simple-debounce';

function SearchComponent() {
  const debounced = useDebounce();

  const handleSearch = (query: string) => {
    debounced(() => performSearch(query), 300);
  };

  return (
    <input
      type="text"
      onChange={e => handleSearch(e.target.value)}
      placeholder="Search..."
    />
  );
}
import { useDebounce } from 'use-simple-debounce';

function SearchComponent() {
  const debounced = useDebounce();

  const handleSearch = (query: string) => {
    debounced(() => performSearch(query), 300);
  };

  return (
    <input
      type="text"
      onChange={e => handleSearch(e.target.value)}
      placeholder="Search..."
    />
  );
}
<template>
  <input v-model="query" @input="handleInputChange" placeholder="Search..." />
</template>

<script setup>
import { ref } from 'vue';
import { useDebounce } from 'use-simple-debounce/vue';

const query = ref('');
const debounced = useDebounce();

const handleInputChange = () => {
  debounced(() => performSearch(query.value), 300);
};
</script>
<template>
  <input v-model="query" @input="handleInputChange" placeholder="Search..." />
</template>

<script setup>
import { ref } from 'vue';
import { useDebounce } from 'use-simple-debounce/vue';

const query = ref('');
const debounced = useDebounce();

const handleInputChange = () => {
  debounced(() => performSearch(query.value), 300);
};
</script>
import { createDebounce } from 'use-simple-debounce/solid';

function SearchComponent() {
  const debounced = createDebounce();

  const handleSearch = (query: string) => {
    debounced(() => performSearch(query), 300);
  };

  return (
    <input
      type="text"
      onInput={e => handleSearch(e.target.value)}
      placeholder="Search..."
    />
  );
}
import { createDebounce } from 'use-simple-debounce/solid';

function SearchComponent() {
  const debounced = createDebounce();

  const handleSearch = (query: string) => {
    debounced(() => performSearch(query), 300);
  };

  return (
    <input
      type="text"
      onInput={e => handleSearch(e.target.value)}
      placeholder="Search..."
    />
  );
}
<script>
  import { createDebounce } from 'use-simple-debounce/svelte';

  let query = '';
  const debounced = createDebounce();

  function handleInputChange(event) {
    const value = event.target.value;
    debounced(() => performSearch(value), 300);
  }
</script>

<input bind:value={query} on:input={handleInputChange} placeholder="Search..." />
<script>
  import { createDebounce } from 'use-simple-debounce/svelte';

  let query = '';
  const debounced = createDebounce();

  function handleInputChange(event) {
    const value = event.target.value;
    debounced(() => performSearch(value), 300);
  }
</script>

<input bind:value={query} on:input={handleInputChange} placeholder="Search..." />
<script>
  import { createDebounce } from 'use-simple-debounce/svelte';

  let query = $state('');
  const debounced = createDebounce();

  function handleInputChange(event) {
    const value = event.target.value;
    debounced(() => performSearch(value), 300);
  }
</script>

<input bind:value={query} oninput={handleInputChange} placeholder="Search..." />
<script>
  import { createDebounce } from 'use-simple-debounce/svelte';

  let query = $state('');
  const debounced = createDebounce();

  function handleInputChange(event) {
    const value = event.target.value;
    debounced(() => performSearch(value), 300);
  }
</script>

<input bind:value={query} oninput={handleInputChange} placeholder="Search..." />
import { useDebounce } from 'use-simple-debounce/vanilla';

const debounced = useDebounce();

function handleSearch(query) {
  debounced(() => performSearch(query), 300);
}

const input = document.querySelector('input');
input.addEventListener('input', e => handleSearch(e.target.value));
import { useDebounce } from 'use-simple-debounce/vanilla';

const debounced = useDebounce();

function handleSearch(query) {
  debounced(() => performSearch(query), 300);
}

const input = document.querySelector('input');
input.addEventListener('input', e => handleSearch(e.target.value));

A lightweight debounce utility for React, Solid, Svelte, Vue, and vanilla JavaScript. Zero dependencies, TypeScript support, and async function handling.

Zero dependencies
TypeScript support
Async function support

Inner Workings

Curious about how it works under the hood? Here's the complete source code for each framework implementation.

import { useRef, useEffect } from 'react';

export function useDebounce() {
  const timeout = useRef<ReturnType<typeof setTimeout> | null>(null);

  useEffect(() => {
    return () => {
      if (timeout.current) {
        clearTimeout(timeout.current);
      }
    };
  }, []);

  return (fn: () => void, delay: number = 300) => {
    if (timeout.current) {
      clearTimeout(timeout.current);
    }
    timeout.current = setTimeout(() => {
      fn();
      timeout.current = null;
    }, delay);
  };
}
import { useRef, useEffect } from 'react';

export function useDebounce() {
  const timeout = useRef<ReturnType<typeof setTimeout> | null>(null);

  useEffect(() => {
    return () => {
      if (timeout.current) {
        clearTimeout(timeout.current);
      }
    };
  }, []);

  return (fn: () => void, delay: number = 300) => {
    if (timeout.current) {
      clearTimeout(timeout.current);
    }
    timeout.current = setTimeout(() => {
      fn();
      timeout.current = null;
    }, delay);
  };
}
import { ref, onUnmounted } from 'vue';

export function useDebounce() {
  const timeout = ref<ReturnType<typeof setTimeout> | null>(null);

  onUnmounted(() => {
    if (timeout.value) {
      clearTimeout(timeout.value);
    }
  });

  return (fn: () => void, delay: number = 300) => {
    if (timeout.value) {
      clearTimeout(timeout.value);
    }
    timeout.value = setTimeout(() => {
      fn();
      timeout.value = null;
    }, delay);
  };
}
import { ref, onUnmounted } from 'vue';

export function useDebounce() {
  const timeout = ref<ReturnType<typeof setTimeout> | null>(null);

  onUnmounted(() => {
    if (timeout.value) {
      clearTimeout(timeout.value);
    }
  });

  return (fn: () => void, delay: number = 300) => {
    if (timeout.value) {
      clearTimeout(timeout.value);
    }
    timeout.value = setTimeout(() => {
      fn();
      timeout.value = null;
    }, delay);
  };
}
import { onCleanup } from 'solid-js';

export function createDebounce() {
  let timeout: ReturnType<typeof setTimeout> | null = null;

  onCleanup(() => {
    if (timeout) {
      clearTimeout(timeout);
    }
  });

  return (fn: () => void, delay: number = 300) => {
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fn();
      timeout = null;
    }, delay);
  };
}
import { onCleanup } from 'solid-js';

export function createDebounce() {
  let timeout: ReturnType<typeof setTimeout> | null = null;

  onCleanup(() => {
    if (timeout) {
      clearTimeout(timeout);
    }
  });

  return (fn: () => void, delay: number = 300) => {
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fn();
      timeout = null;
    }, delay);
  };
}
import { onDestroy } from 'svelte';

export function createDebounce() {
  let timeout: ReturnType<typeof setTimeout> | null = null;

  onDestroy(() => {
    if (timeout) {
      clearTimeout(timeout);
    }
  });

  return (fn: () => void, delay: number = 300) => {
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fn();
      timeout = null;
    }, delay);
  };
}
import { onDestroy } from 'svelte';

export function createDebounce() {
  let timeout: ReturnType<typeof setTimeout> | null = null;

  onDestroy(() => {
    if (timeout) {
      clearTimeout(timeout);
    }
  });

  return (fn: () => void, delay: number = 300) => {
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fn();
      timeout = null;
    }, delay);
  };
}
export function useDebounce() {

  let timeoutId: ReturnType<typeof setTimeout> | undefined;

  return (fn: () => void, delay: number = 300): (() => void) => {

    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => fn(), delay);

    return () => {
      clearTimeout(timeoutId);
    };

  };
}
export function useDebounce() {

  let timeoutId: ReturnType<typeof setTimeout> | undefined;

  return (fn: () => void, delay: number = 300): (() => void) => {

    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => fn(), delay);

    return () => {
      clearTimeout(timeoutId);
    };

  };
}