Docs
CodeRabbit
Cloudflare
AG Grid
SerpAPI
Netlify
OpenRouter
Neon
WorkOS
Clerk
Electric
PowerSync
Sentry
Railway
Prisma
Strapi
Unkey
CodeRabbit
Cloudflare
AG Grid
SerpAPI
Netlify
OpenRouter
Neon
WorkOS
Clerk
Electric
PowerSync
Sentry
Railway
Prisma
Strapi
Unkey
Debouncer API Reference
Throttler API Reference
Rate Limiter API Reference
Queue API Reference
Batcher API Reference

Svelte Example: CreateDebouncer

<script lang="ts">
  import { TanStackDevtools } from '@tanstack/svelte-devtools'
  import { pacerDevtoolsPlugin } from '@tanstack/svelte-pacer-devtools'
  import { createDebouncer } from '@tanstack/svelte-pacer/debouncer'

  let instantCount = $state(0)
  let debouncedCount = $state(0)
  const debouncer = createDebouncer(
    (count: number) => {
      debouncedCount = count
    },
    {
      key: 'counter',
      wait: 800,
      enabled: () => instantCount > 2,
      // leading: true, // optional, defaults to false
    },
    // Alternative to Subscribe: select state here to update this component.
    // (state) => state,
  )

  function increment() {
    debouncer.maybeExecute(++instantCount)
  }

  let searchText = $state('')
  let debouncedSearchText = $state('')
  const setSearchDebouncer = createDebouncer(
    (value: string) => {
      debouncedSearchText = value
    },
    { key: 'search', wait: 500, enabled: () => searchText.length > 2 },
  )

  function handleSearchChange(event: Event) {
    searchText = (event.target as HTMLInputElement).value
    setSearchDebouncer.maybeExecute(searchText)
  }

  let currentValue = $state(50)
  let debouncedValue = $state(50)
  let instantExecutionCount = $state(0)
  let wait = $state(250)
  let enabled = $state(true)
  const setValueDebouncer = createDebouncer(
    (value: number) => {
      debouncedValue = value
    },
    () => ({ key: 'range', wait: wait, enabled: enabled }),
  )

  function handleRangeChange(event: Event) {
    currentValue = (event.target as HTMLInputElement).valueAsNumber
    instantExecutionCount++
    setValueDebouncer.maybeExecute(currentValue)
  }
</script>

<div>
  <div>
    <h1>TanStack Pacer createDebouncer Example 1</h1>
    <table>
      <tbody>
        <debouncer.Subscribe
          selector={(state) => ({
            status: state.status,
            executionCount: state.executionCount,
          })}
        >
          {#snippet children({ status, executionCount })}
            <tr><td>Status:</td><td>{status}</td></tr>
            <tr><td>Execution Count:</td><td>{executionCount}</td></tr>
          {/snippet}
        </debouncer.Subscribe>
        <tr><td colspan="2"><hr /></td></tr>
        <tr><td>Instant Count:</td><td>{instantCount}</td></tr>
        <tr><td>Debounced Count:</td><td>{debouncedCount}</td></tr>
      </tbody>
    </table>
    <div>
      <button onclick={increment}>Increment</button><button
        onclick={() => debouncer.flush()}
        style="margin-left: 10px">Flush</button
      >
    </div>
    <debouncer.Subscribe selector={(state) => state}>
      {#snippet children(state)}
        <pre style="margin-top: 20px">{JSON.stringify(state, null, 2)}</pre>
      {/snippet}
    </debouncer.Subscribe>
  </div>
  <hr />
  <div>
    <h1>TanStack Pacer createDebouncer Example 2</h1>
    <div>
      <!-- svelte-ignore a11y_autofocus -->
      <input
        autofocus
        type="search"
        value={searchText}
        oninput={handleSearchChange}
        placeholder="Type to search..."
        style="width: 100%; margin-bottom: 1rem"
      />
    </div>
    <table>
      <tbody>
        <setSearchDebouncer.Subscribe
          selector={(state) => ({
            isPending: state.isPending,
            executionCount: state.executionCount,
          })}
        >
          {#snippet children({ isPending, executionCount })}
            <tr><td>Is Pending:</td><td>{isPending.toString()}</td></tr>
            <tr><td>Execution Count:</td><td>{executionCount}</td></tr>
          {/snippet}
        </setSearchDebouncer.Subscribe>
        <tr><td colspan="2"><hr /></td></tr>
        <tr><td>Instant Search:</td><td>{searchText}</td></tr>
        <tr><td>Debounced Search:</td><td>{debouncedSearchText}</td></tr>
      </tbody>
    </table>
    <div><button onclick={() => setSearchDebouncer.flush()}>Flush</button></div>
    <setSearchDebouncer.Subscribe selector={(state) => state}>
      {#snippet children(state)}
        <pre style="margin-top: 20px">{JSON.stringify(state, null, 2)}</pre>
      {/snippet}
    </setSearchDebouncer.Subscribe>
  </div>
  <hr />
  <div>
    <h1>TanStack Pacer createDebouncer Example 3</h1>
    <fieldset>
      <legend>Reactive options</legend>
      <label>
        Delay: {wait} ms<input
          type="range"
          min="0"
          max="1500"
          step="50"
          bind:value={wait}
        />
      </label><label
        ><input type="checkbox" bind:checked={enabled} />Enabled</label
      >
      <p>
        Changing the delay affects the next scheduled call. Disabling cancels
        pending work.
      </p>
    </fieldset>
    <div style="margin-bottom: 20px">
      <label
        >Current Range:<input
          type="range"
          min="0"
          max="100"
          value={currentValue}
          oninput={handleRangeChange}
          style="width: 100%"
        /><span>{currentValue}</span>
      </label>
    </div>
    <div style="margin-bottom: 20px">
      <label
        >Debounced Range (Readonly):<input
          type="range"
          min="0"
          max="100"
          value={debouncedValue}
          disabled
          style="width: 100%"
        /><span>{debouncedValue}</span>
      </label>
    </div>
    <table>
      <tbody>
        <setValueDebouncer.Subscribe
          selector={(state) => ({
            isPending: state.isPending,
            executionCount: state.executionCount,
          })}
        >
          {#snippet children({ isPending, executionCount })}
            <tr><td>Is Pending:</td><td>{isPending.toString()}</td></tr>
            <tr><td>Instant Executions:</td><td>{instantExecutionCount}</td></tr
            >
            <tr><td>Debounced Executions:</td><td>{executionCount}</td></tr>
            <tr
              ><td>Saved Executions:</td><td
                >{instantExecutionCount - executionCount}</td
              ></tr
            >
            <tr
              ><td>% Reduction:</td><td
                >{instantExecutionCount === 0
                  ? '0'
                  : Math.round(
                      ((instantExecutionCount - executionCount) /
                        instantExecutionCount) *
                        100,
                    )}%</td
              ></tr
            >
          {/snippet}
        </setValueDebouncer.Subscribe>
      </tbody>
    </table>
    <div style="color: #666; font-size: 0.9em">
      <p>Debounced to {wait}ms wait time</p>
    </div>
    <div><button onclick={() => setValueDebouncer.flush()}>Flush</button></div>
    <setValueDebouncer.Subscribe selector={(state) => state}>
      {#snippet children(state)}
        <pre style="margin-top: 20px">{JSON.stringify(state, null, 2)}</pre>
      {/snippet}
    </setValueDebouncer.Subscribe>
  </div>
</div>

{#if import.meta.env.DEV}
  <TanStackDevtools plugins={[pacerDevtoolsPlugin()]} />
{/if}
<script lang="ts">
  import { TanStackDevtools } from '@tanstack/svelte-devtools'
  import { pacerDevtoolsPlugin } from '@tanstack/svelte-pacer-devtools'
  import { createDebouncer } from '@tanstack/svelte-pacer/debouncer'

  let instantCount = $state(0)
  let debouncedCount = $state(0)
  const debouncer = createDebouncer(
    (count: number) => {
      debouncedCount = count
    },
    {
      key: 'counter',
      wait: 800,
      enabled: () => instantCount > 2,
      // leading: true, // optional, defaults to false
    },
    // Alternative to Subscribe: select state here to update this component.
    // (state) => state,
  )

  function increment() {
    debouncer.maybeExecute(++instantCount)
  }

  let searchText = $state('')
  let debouncedSearchText = $state('')
  const setSearchDebouncer = createDebouncer(
    (value: string) => {
      debouncedSearchText = value
    },
    { key: 'search', wait: 500, enabled: () => searchText.length > 2 },
  )

  function handleSearchChange(event: Event) {
    searchText = (event.target as HTMLInputElement).value
    setSearchDebouncer.maybeExecute(searchText)
  }

  let currentValue = $state(50)
  let debouncedValue = $state(50)
  let instantExecutionCount = $state(0)
  let wait = $state(250)
  let enabled = $state(true)
  const setValueDebouncer = createDebouncer(
    (value: number) => {
      debouncedValue = value
    },
    () => ({ key: 'range', wait: wait, enabled: enabled }),
  )

  function handleRangeChange(event: Event) {
    currentValue = (event.target as HTMLInputElement).valueAsNumber
    instantExecutionCount++
    setValueDebouncer.maybeExecute(currentValue)
  }
</script>

<div>
  <div>
    <h1>TanStack Pacer createDebouncer Example 1</h1>
    <table>
      <tbody>
        <debouncer.Subscribe
          selector={(state) => ({
            status: state.status,
            executionCount: state.executionCount,
          })}
        >
          {#snippet children({ status, executionCount })}
            <tr><td>Status:</td><td>{status}</td></tr>
            <tr><td>Execution Count:</td><td>{executionCount}</td></tr>
          {/snippet}
        </debouncer.Subscribe>
        <tr><td colspan="2"><hr /></td></tr>
        <tr><td>Instant Count:</td><td>{instantCount}</td></tr>
        <tr><td>Debounced Count:</td><td>{debouncedCount}</td></tr>
      </tbody>
    </table>
    <div>
      <button onclick={increment}>Increment</button><button
        onclick={() => debouncer.flush()}
        style="margin-left: 10px">Flush</button
      >
    </div>
    <debouncer.Subscribe selector={(state) => state}>
      {#snippet children(state)}
        <pre style="margin-top: 20px">{JSON.stringify(state, null, 2)}</pre>
      {/snippet}
    </debouncer.Subscribe>
  </div>
  <hr />
  <div>
    <h1>TanStack Pacer createDebouncer Example 2</h1>
    <div>
      <!-- svelte-ignore a11y_autofocus -->
      <input
        autofocus
        type="search"
        value={searchText}
        oninput={handleSearchChange}
        placeholder="Type to search..."
        style="width: 100%; margin-bottom: 1rem"
      />
    </div>
    <table>
      <tbody>
        <setSearchDebouncer.Subscribe
          selector={(state) => ({
            isPending: state.isPending,
            executionCount: state.executionCount,
          })}
        >
          {#snippet children({ isPending, executionCount })}
            <tr><td>Is Pending:</td><td>{isPending.toString()}</td></tr>
            <tr><td>Execution Count:</td><td>{executionCount}</td></tr>
          {/snippet}
        </setSearchDebouncer.Subscribe>
        <tr><td colspan="2"><hr /></td></tr>
        <tr><td>Instant Search:</td><td>{searchText}</td></tr>
        <tr><td>Debounced Search:</td><td>{debouncedSearchText}</td></tr>
      </tbody>
    </table>
    <div><button onclick={() => setSearchDebouncer.flush()}>Flush</button></div>
    <setSearchDebouncer.Subscribe selector={(state) => state}>
      {#snippet children(state)}
        <pre style="margin-top: 20px">{JSON.stringify(state, null, 2)}</pre>
      {/snippet}
    </setSearchDebouncer.Subscribe>
  </div>
  <hr />
  <div>
    <h1>TanStack Pacer createDebouncer Example 3</h1>
    <fieldset>
      <legend>Reactive options</legend>
      <label>
        Delay: {wait} ms<input
          type="range"
          min="0"
          max="1500"
          step="50"
          bind:value={wait}
        />
      </label><label
        ><input type="checkbox" bind:checked={enabled} />Enabled</label
      >
      <p>
        Changing the delay affects the next scheduled call. Disabling cancels
        pending work.
      </p>
    </fieldset>
    <div style="margin-bottom: 20px">
      <label
        >Current Range:<input
          type="range"
          min="0"
          max="100"
          value={currentValue}
          oninput={handleRangeChange}
          style="width: 100%"
        /><span>{currentValue}</span>
      </label>
    </div>
    <div style="margin-bottom: 20px">
      <label
        >Debounced Range (Readonly):<input
          type="range"
          min="0"
          max="100"
          value={debouncedValue}
          disabled
          style="width: 100%"
        /><span>{debouncedValue}</span>
      </label>
    </div>
    <table>
      <tbody>
        <setValueDebouncer.Subscribe
          selector={(state) => ({
            isPending: state.isPending,
            executionCount: state.executionCount,
          })}
        >
          {#snippet children({ isPending, executionCount })}
            <tr><td>Is Pending:</td><td>{isPending.toString()}</td></tr>
            <tr><td>Instant Executions:</td><td>{instantExecutionCount}</td></tr
            >
            <tr><td>Debounced Executions:</td><td>{executionCount}</td></tr>
            <tr
              ><td>Saved Executions:</td><td
                >{instantExecutionCount - executionCount}</td
              ></tr
            >
            <tr
              ><td>% Reduction:</td><td
                >{instantExecutionCount === 0
                  ? '0'
                  : Math.round(
                      ((instantExecutionCount - executionCount) /
                        instantExecutionCount) *
                        100,
                    )}%</td
              ></tr
            >
          {/snippet}
        </setValueDebouncer.Subscribe>
      </tbody>
    </table>
    <div style="color: #666; font-size: 0.9em">
      <p>Debounced to {wait}ms wait time</p>
    </div>
    <div><button onclick={() => setValueDebouncer.flush()}>Flush</button></div>
    <setValueDebouncer.Subscribe selector={(state) => state}>
      {#snippet children(state)}
        <pre style="margin-top: 20px">{JSON.stringify(state, null, 2)}</pre>
      {/snippet}
    </setValueDebouncer.Subscribe>
  </div>
</div>

{#if import.meta.env.DEV}
  <TanStackDevtools plugins={[pacerDevtoolsPlugin()]} />
{/if}