# Timer

A React component in [Beamline](https://beamline.io/)'s [Feedback](https://beamline.io/components/feedback) category. Live demo: https://beamline.io/components/timer

A duration that counts down (or up) from your clock: Start, Pause, Resume, Reset and the finish reported once; the time left drawn as a bar you drag (or step with ←/→) to give more or less time; a compact inline button for a timed round beside its value; resumes right after the page was away.

## Use it for

- A rest between rounds, a timed set or drill, a cooking step, a focus block: any short duration a person starts, pauses and adjusts by feel.
- Counting time up since a start (a session, a call) with Pause and Reset.

## Not for

- A deadline at a date and time (a date with relative words, or [funding-countdown](https://beamline.io/components/funding-countdown) for a market's next funding).
- Time spent while saving or loading (useElapsed and the part's own busy state).
- Picking a time of day ([time-picker](https://beamline.io/components/time-picker)).

## Anatomy

- large: what it times, the time in large tabular digits with its word (left, paused, elapsed, done), the time left as a bar (the whole duration faint behind it), Start/Pause/Resume and Reset
- inline: one button with Play, Pause or a check and the time
- a polite status line that says the finish once

## States

- idle
- running
- paused (digits dimmed, said)
- done (success tone with the word, Start again)
- counting up (no bar)
- resumed after the page was away
- finished while away (done on return, reported once)
- bar held (the value beside the hand)
- inline: idle, running, paused, done

## Keyboard

- Start/Pause and Reset are buttons
- the bar (a slider, when the duration can change): → / ← five seconds (Shift: thirty), mirrored right to left
- inline: Enter or Space starts and pauses

## Motion

The digits change once a second while running and never animate; the bar steps with them. Nothing renders or runs while idle, paused or done. Reduced motion changes nothing (nothing glides).

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `label` (required) | `string` | — | What it times, said with every value: "Rest", "Plank, set 2". |
| `duration / onDurationChange` (required) | `number \| null / (seconds) => void` | — | duration: Seconds to count down; null counts up (time since start) with no end. onDurationChange: Or change the duration (the bar, its keys). Without it the duration is fixed. |
| `state / defaultState / onStateChange` | `TimerState` | — | { status, elapsedMs, runningSince }: store it and the timer resumes right after a reload. |
| `onComplete` | `() => void` | — | The countdown reached zero: called once per run (also when it finished while the page was away). |
| `form` | `"large" \| "inline"` | — | large: digits, a bar you can drag, Start/Pause and Reset. inline: one compact button beside a value. |
| `step / max` | `number` | — | step: Seconds the bar and its keys step by. Default 5. max: The longest duration the bar reaches, in seconds. Default twice the duration (at least a minute, in 30 s), so a rest has room to grow; it changes only after a release, never under the hand. |
| `clock` | `() => number` | — | Your clock (ms since the epoch). Default Date.now. |
| `labels` | `MessageLabels` | — | Your words for the built-in ones. |
| `duration` (required) | `number \| null` | — | Seconds to count down; null counts up (time since start) with no end. |
| `onDurationChange` | `((seconds: number) => void)` | — | Or change the duration (the bar, its keys). Without it the duration is fixed. |
| `state` | `TimerState` | — |  |
| `defaultState` | `TimerState` | — |  |
| `onStateChange` | `((state: TimerState) => void)` | — | Every start, pause, resume, reset and the finish, as the whole new state. Store it to survive a reload. |
| `step` | `number` | — | Seconds the bar and its keys step by. Default 5. |
| `max` | `number` | — | The longest duration the bar reaches, in seconds. Default twice the duration (at least a minute, in 30 s), so a rest has room to grow; it changes only after a release, never under the hand. |
| `className` | `string` | — | Classes on the documented visual root; no override by default. |
| `style` | `CSSProperties` | — | Inline styles on the documented visual root; no overrides by default. |
| `ref` | `Ref<HTMLDivElement>` | — | Receives the documented native target or imperative handle; omitted by default. |

## Built from

- [Button](https://beamline.io/components/button.md)
- [Spinner](https://beamline.io/components/spinner.md)

## Used in

- [Program setup](https://beamline.io/components/program-setup.md)
- [Workout logger](https://beamline.io/components/workout-logger.md)

## Dependencies

`lucide-react`

## Import

```tsx
import { Timer, TIMER_IDLE } from "@beamline/timer";
```

## Get it

Timer is part of Beamline UI. Install the parts you need in your React app as compiled packages or editable source. [Get Beamline](https://beamline.io/checkout?pack=complete) · [Connect your agent](https://beamline.io/connect)

## More in Feedback

- [Notification centre](https://beamline.io/components/notification-center): Updates that wait to be read: a bell with the unread count opens All / Unread, new and earlier groups, and per item mark read or dismiss.
- [Usage meter](https://beamline.io/components/usage-meter): An allowance and what fills it: one bar split by source, the room left, a warning near the limit and the overflow in its own red well past a notch at the…
- [Alert](https://beamline.io/components/alert): A message that stays until it is dealt with: what happened, what to do, an action; danger and warning are announced; dismissing folds its height away.
- [Cookie consent](https://beamline.io/components/cookie-consent): Asks once which cookies a visitor allows, with Reject all and Accept all given equal weight; Customise grows the notice in place into each category with…
- [Empty state](https://beamline.io/components/empty-state): What a place will hold and the first step to fill it, instead of a blank; a compact size for panels and filtered tables.
- [Spinner](https://beamline.io/components/spinner): A ring that spins while work runs and closes into a drawn check or cross when it ends.
- [Announcement bar](https://beamline.io/components/announcement-bar): A banner across the top for news and offers: messages take turns, a countdown ticks, and dismissing folds it away and can remember it.
- [Progress](https://beamline.io/components/progress): How much of a known task is done, or a moving bar when the length is unknown, with an optional label and value.
- [Skeleton](https://beamline.io/components/skeleton): Holds the shape of content while it loads, then crossfades into it, so nothing jumps.

Part of [Beamline UI: polished, editable React components and complete screens for custom applications](https://beamline.io/). [Build your own style from any look; tokens, fonts, radii, motion; not only colours](https://beamline.io/docs/customize).
