Primitives to manage timeout and interval
| Stage | Category | Version | Last Updated | Demo |
|---|---|---|---|---|
| 3 | Browser APIs | 1.4.5-next.1 (next) | Aug 16, 2026 | Demo → |
npm i @solid-primitives/timer@nextTimer primitives related to setInterval and setTimeout:
makeTimer- Creates a timer and returns a function to clear it. No reactive lifecycle — the caller decides cleanup.createTimer- Reactive timer with an optionally reactive delay and automatic cleanup.createTimeoutLoop- LikecreateTimerwithsetInterval, but the delay only updates between executions.createPolled- Polls a function periodically and returns an accessor to its latest value.createIntervalCounter- A counter that increments periodically.
How to use it
makeTimer
Creates a timer (setTimeout or setInterval) and returns a function to clear it. This is a base primitive with no reactive lifecycle integration — the caller is responsible for cleanup.
To tie cleanup to a reactive scope, pass the returned function to onCleanup:
import { onCleanup } from "solid-js";import { makeTimer } from "@solid-primitives/timer";
// Manual cleanupconst clear = makeTimer(() => console.log("tick"), 1000, setInterval);// ...clear();
// Tied to a reactive scopeonCleanup(makeTimer(() => console.log("tick"), 1000, setInterval));createTimer
A reactive timer whose delay can be a static number or a reactive accessor. When the delay accessor returns false, the timer is disabled. Automatically cleans up when the reactive scope is disposed.
When the delay changes, the elapsed fraction of the previous delay carries forward — so changing from 1000ms to 2000ms after 250ms elapsed will fire the next callback after 1500ms, not 2000ms.
import { createSignal } from "solid-js";import { createTimer } from "@solid-primitives/timer";
// Static delaycreateTimer(() => console.log("timeout"), 1000, setTimeout);createTimer(() => console.log("interval"), 1000, setInterval);
// Reactive delay with pause supportconst [paused, setPaused] = createSignal(false);const [delay, setDelay] = createSignal(1000);
createTimer( () => console.log("tick"), () => !paused() && delay(), setInterval,);
setDelay(500); // change intervalsetPaused(true); // pausesetPaused(false); // resumecreateTimeoutLoop
Similar to createTimer with setInterval, but the delay is only read between executions rather than reactively. This means a delay change takes effect after the current interval completes.
import { createSignal } from "solid-js";import { createTimeoutLoop } from "@solid-primitives/timer";
// Static delaycreateTimeoutLoop(() => console.log("loop"), 1000);
// Reactive delay — updates between executionsconst [delay, setDelay] = createSignal(1000);createTimeoutLoop(() => console.log("loop"), delay);// ...setDelay(500); // takes effect after the current interval firescreatePolled
Polls a function periodically and returns an accessor to its latest return value. The function is called immediately on creation, then after each interval. If the polling function reads reactive signals, the accessor also updates when those signals change.
import { createSignal } from "solid-js";import { createPolled } from "@solid-primitives/timer";
// Poll current time every secondconst date = createPolled(() => new Date(), 1000);<span>The time is: {date()}</span>;
// Reactive source — updates on interval AND when source changesconst [id, setId] = createSignal(1);const user = createPolled(() => cache.get(id()), 5000);
// Reactive delayconst [delay, setDelay] = createSignal(1000);const polled = createPolled(() => new Date(), delay);setDelay(500);createIntervalCounter
A counter that starts at 0 and increments by one each interval. Accepts a static or reactive delay.
import { createSignal } from "solid-js";import { createIntervalCounter } from "@solid-primitives/timer";
const count = createIntervalCounter(1000);<span>Count: {count()}</span>;
// Reactive delayconst [delay, setDelay] = createSignal(1000);const count = createIntervalCounter(delay);setDelay(500);Note on Reactive Delays
When a delay changes, the fraction of the current interval already elapsed carries over to the new delay. For example, if a 1000ms delay is changed to 2000ms after 250ms (25% done), the first callback with the new delay fires after 1500ms (75% of 2000ms), and subsequent callbacks fire every 2000ms.
Changelog
See CHANGELOG.md