11# @crup/react-timer-hook
22
3- > Deterministic React timer primitives for countdowns, stopwatches, clocks, schedules, and many independent timers .
3+ > Reliable React timer hooks for countdowns, stopwatches, clocks, polling schedules, and many independent timer lifecycles .
44
55[ ![ npm alpha] ( https://img.shields.io/npm/v/%40crup%2Freact-timer-hook/alpha?label=npm%20alpha&color=00b894 )] ( https://www.npmjs.com/package/@crup/react-timer-hook?activeTab=versions )
66[ ![ npm downloads] ( https://img.shields.io/npm/dm/%40crup%2Freact-timer-hook?color=0f766e )] ( https://www.npmjs.com/package/@crup/react-timer-hook )
77[ ![ CI] ( https://github.com/crup/react-timer-hook/actions/workflows/ci.yml/badge.svg )] ( https://github.com/crup/react-timer-hook/actions/workflows/ci.yml )
88[ ![ Docs] ( https://github.com/crup/react-timer-hook/actions/workflows/docs.yml/badge.svg )] ( https://github.com/crup/react-timer-hook/actions/workflows/docs.yml )
99[ ![ Size] ( https://github.com/crup/react-timer-hook/actions/workflows/size.yml/badge.svg )] ( https://github.com/crup/react-timer-hook/actions/workflows/size.yml )
1010[ ![ license] ( https://img.shields.io/npm/l/%40crup%2Freact-timer-hook?color=111827 )] ( ./LICENSE )
11- [ ![ types] ( https://img.shields.io/npm/types/%40crup%2Freact-timer-hook?color=2563eb )] ( ./dist/index.d.ts )
11+ [ ![ types] ( https://img.shields.io/npm/types/%40crup%2Freact-timer-hook?color=2563eb )] ( https://www.npmjs.com/package/@crup/react-timer-hook )
12+ [ ![ React] ( https://img.shields.io/npm/dependency-version/%40crup%2Freact-timer-hook/peer/react?label=react&color=149eca )] ( https://react.dev/ )
1213
13- 📚 Docs: https://crup.github.io/react-timer-hook/
14+ 📚 Docs and live examples : https://crup.github.io/react-timer-hook/
1415
15- ## Docs and live examples
16+ ## Why this exists
1617
17- The documentation site is built with Docusaurus and includes live React playgrounds for 15 recipes:
18+ Timer hooks look simple until real apps need pause/resume semantics, Strict Mode cleanup, async callbacks, polling that does not overlap, and lists with dozens of independent timers.
1819
19- - Basic: clock, stopwatch, absolute countdown, pausable countdown, manual controls
20- - Intermediate: once-only ` onEnd ` , polling, poll-and-cancel, backend events, debug logs
21- - Advanced: many display timers, timer groups, global controls, per-item polling, dynamic items
20+ ` @crup/react-timer-hook ` keeps the API small and lets your app decide what time means:
2221
23- Open: https://crup.github.io/react-timer-hook/
24-
25- ## Why it is different
26-
27- Most timer libraries mix scheduling, lifecycle, formatting, and app behavior. This package keeps the core small:
28-
29- - ⏱️ ` useTimer() ` for one lifecycle.
22+ - ⏱️ ` useTimer() ` for one lifecycle: stopwatch, countdown, clock, schedule, or custom flow.
3023- 🧭 ` useTimerGroup() ` for many keyed lifecycles with one shared scheduler.
31- - 🧩 ` durationParts() ` for display-friendly duration math.
32- - 🧼 No timezone, locale, or formatting opinions .
33- - 🧪 Built around React Strict Mode, rerenders, async callbacks, and cleanup .
34- - 🤖 AI -friendly docs via ` llms.txt ` , ` llms-full.txt ` , and a tiny local MCP docs utility .
24+ - 🧩 ` durationParts() ` for display math without locale or timezone opinions .
25+ - 🧼 No formatting, timezone, audio, retry, cache, or data-fetching policy baked in .
26+ - 🧪 Built for rerenders, Strict Mode, async callbacks, cleanup, and many timers .
27+ - 🤖 Agent -friendly docs through hosted ` llms.txt ` , ` llms-full.txt ` , and an optional MCP docs helper .
3528
3629## Install
3730
38- Alpha is the only intended release channel until stable publishing is explicitly unlocked .
31+ The project is currently in alpha while the API receives feedback .
3932
4033``` sh
4134npm install @crup/react-timer-hook@alpha
4235pnpm add @crup/react-timer-hook@alpha
4336```
4437
45- ``` ts
38+ ``` tsx
4639import { durationParts , useTimer , useTimerGroup } from ' @crup/react-timer-hook' ;
4740```
4841
42+ ## Live recipes
43+
44+ Each recipe has a live playground and a focused code sample:
45+
46+ - Basic: [ wall clock] ( https://crup.github.io/react-timer-hook/recipes/basic/wall-clock/ ) , [ stopwatch] ( https://crup.github.io/react-timer-hook/recipes/basic/stopwatch/ ) , [ absolute countdown] ( https://crup.github.io/react-timer-hook/recipes/basic/absolute-countdown/ ) , [ pausable countdown] ( https://crup.github.io/react-timer-hook/recipes/basic/pausable-countdown/ ) , [ manual controls] ( https://crup.github.io/react-timer-hook/recipes/basic/manual-controls/ )
47+ - Intermediate: [ once-only onEnd] ( https://crup.github.io/react-timer-hook/recipes/intermediate/once-only-on-end/ ) , [ polling schedule] ( https://crup.github.io/react-timer-hook/recipes/intermediate/polling-schedule/ ) , [ poll and cancel] ( https://crup.github.io/react-timer-hook/recipes/intermediate/poll-and-cancel/ ) , [ backend event stop] ( https://crup.github.io/react-timer-hook/recipes/intermediate/backend-event-stop/ ) , [ debug logs] ( https://crup.github.io/react-timer-hook/recipes/intermediate/debug-logs/ )
48+ - Advanced: [ many display countdowns] ( https://crup.github.io/react-timer-hook/recipes/advanced/many-display-countdowns/ ) , [ timer group] ( https://crup.github.io/react-timer-hook/recipes/advanced/timer-group/ ) , [ group controls] ( https://crup.github.io/react-timer-hook/recipes/advanced/group-controls/ ) , [ per-item polling] ( https://crup.github.io/react-timer-hook/recipes/advanced/per-item-polling/ ) , [ dynamic items] ( https://crup.github.io/react-timer-hook/recipes/advanced/dynamic-items/ )
49+
4950## Quick examples
5051
5152### Stopwatch
@@ -58,17 +59,17 @@ export function Stopwatch() {
5859
5960 return (
6061 <>
61- <output >{ Math . floor (timer .elapsedMilliseconds / 1000 )} s</output >
62- <button onClick = { timer .start } >Start</button >
63- <button onClick = { timer .pause } >Pause</button >
64- <button onClick = { timer .resume } >Resume</button >
62+ <output >{ (timer .elapsedMilliseconds / 1000 ). toFixed ( 1 )} s</output >
63+ <button disabled = { ! timer . isIdle } onClick = { timer .start } >Start</button >
64+ <button disabled = { ! timer . isRunning } onClick = { timer .pause } >Pause</button >
65+ <button disabled = { ! timer . isPaused } onClick = { timer .resume } >Resume</button >
6566 <button onClick = { timer .restart } >Restart</button >
6667 </>
6768 );
6869}
6970```
7071
71- ### Absolute countdown
72+ ### Auction countdown
7273
7374Use ` now ` for wall-clock deadlines from a server, auction, reservation, or job expiry.
7475
@@ -93,7 +94,7 @@ export function AuctionTimer({ auctionId, expiresAt }: {
9394}
9495```
9596
96- ### Polling with early cancel
97+ ### Poll and cancel early
9798
9899Schedules run while the timer is active. Slow async work is skipped by default with ` overlap: 'skip' ` .
99100
@@ -134,29 +135,24 @@ const timers = useTimerGroup({
134135
135136## Bundle size
136137
137- Current local build:
138+ Current build:
138139
139140| File | Raw | Gzip | Brotli |
140141| --- | ---: | ---: | ---: |
141142| ` dist/index.js ` | 11.82 kB | 3.55 kB | 3.20 kB |
142143| ` dist/index.cjs ` | 12.94 kB | 3.79 kB | 3.42 kB |
143144| ` dist/index.d.ts ` | 3.95 kB | 992 B | 888 B |
144145
145- CI writes a size summary to the GitHub Actions UI and posts a bundle-size comment on pull requests.
146+ CI writes a size summary to the GitHub Actions UI and posts bundle-size reports on pull requests.
146147
147- ## AI-friendly
148+ ## AI-friendly docs
148149
149- End users do not need these files. They are for coding agents, docs-aware IDEs, and MCP clients.
150+ Agents and docs-aware IDEs can use:
150151
151- ### MCP setup
152+ - https://crup.github.io/react-timer-hook/llms.txt
153+ - https://crup.github.io/react-timer-hook/llms-full.txt
152154
153- Clone the repo, install dependencies, and point your MCP client at the local stdio server:
154-
155- ``` sh
156- git clone https://github.com/crup/react-timer-hook.git
157- cd react-timer-hook
158- pnpm install
159- ```
155+ Optional local MCP docs server:
160156
161157``` json
162158{
@@ -169,37 +165,20 @@ pnpm install
169165}
170166```
171167
172- The MCP server exposes:
168+ It exposes:
173169
174170``` txt
175171react-timer-hook://package
176172react-timer-hook://api
177173react-timer-hook://recipes
178174```
179175
180- Agents can use hosted context:
181-
182- - https://crup.github.io/react-timer-hook/llms.txt
183- - https://crup.github.io/react-timer-hook/llms-full.txt
184-
185- Local MCP/docs helpers:
186-
187- ``` sh
188- pnpm ai:context
189- pnpm mcp:docs
190- ```
191-
192- The MCP utility is repo-local and excluded from the published npm package.
193-
194- ## Release policy
176+ ## Contributing
195177
196- - Published versions must stay ` 0.0.1-alpha.x ` until stable release is explicitly unlocked.
197- - ` @alpha ` is the documented install tag right now.
198- - Npm requires a ` latest ` dist-tag, so the workflow keeps ` latest ` pointing at the current alpha until stable publishing is unlocked.
178+ Issues, recipes, docs improvements, and focused bug reports are welcome.
199179
200- ## Links
180+ - Read the docs: https://crup.github.io/react-timer-hook/
181+ - Open an issue: https://github.com/crup/react-timer-hook/issues
182+ - See the contributing guide: ./CONTRIBUTING.md
201183
202- - 📚 Docs: https://crup.github.io/react-timer-hook/
203- - 📦 npm: https://www.npmjs.com/package/@crup/react-timer-hook
204- - 🧵 Issues: https://github.com/crup/react-timer-hook/issues
205- - 🤝 Contributing: ./CONTRIBUTING.md
184+ The package targets Node 24 for development and React 18+ as a peer dependency.
0 commit comments