Timer
The timer machine is used to record the time elapsed from zero or since a specified target time.
Features
- Countdown from a specified time
- Use as stopwatch to record the time elapsed
- Control the timer with start, stop, and resume buttons
- Set the tick interval for the timer
Installation
To use the Timer machine in your project, run the following command in your command line:
npm install @zag-js/timer @zag-js/react # or yarn add @zag-js/timer @zag-js/react
npm install @zag-js/timer @zag-js/solid # or yarn add @zag-js/timer @zag-js/solid
npm install @zag-js/timer @zag-js/vue # or yarn add @zag-js/timer @zag-js/vue
npm install @zag-js/timer @zag-js/svelte # or yarn add @zag-js/timer @zag-js/svelte
Anatomy
To set up the Timer correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-partattribute to help identify them in the DOM.
Usage
First, import the timer package into your project
import * as timer from "@zag-js/timer"
The Timer package exports these functions:
machine— The state machine logic for the Time Picker widget.connect— The function that translates the machine's state to JSX attributes and event handlers.parse— The function to parse a date time string or object into aTimeobject.
You'll also need to provide a unique
idto theuseMachinehook. This is used to ensure that every part has a unique identifier.
Next, import the required hooks and functions for your framework and use the Time Picker machine in your project 🔥
import { normalizeProps, useMachine } from "@zag-js/react" import * as timer from "@zag-js/timer" export function Countdown() { const service = useMachine(timer.machine, { id: useId(), countdown: true, autoStart: true, startMs: timer.parse({ days: 2, seconds: 10 }), }) const api = timer.connect(service, normalizeProps) return ( <div {...api.getRootProps()}> <div {...api.getAreaProps()}> <div {...api.getItemProps({ type: "days" })}> {api.formattedTime.days} </div> <div {...api.getSeparatorProps()}>:</div> <div {...api.getItemProps({ type: "hours" })}> {api.formattedTime.hours} </div> <div {...api.getSeparatorProps()}>:</div> <div {...api.getItemProps({ type: "minutes" })}> {api.formattedTime.minutes} </div> <div {...api.getSeparatorProps()}>:</div> <div {...api.getItemProps({ type: "seconds" })}> {api.formattedTime.seconds} </div> </div> <div {...api.getControlProps()}> <button {...api.getActionTriggerProps({ action: "start" })}> START </button> <button {...api.getActionTriggerProps({ action: "pause" })}> PAUSE </button> <button {...api.getActionTriggerProps({ action: "resume" })}> RESUME </button> <button {...api.getActionTriggerProps({ action: "reset" })}> RESET </button> </div> </div> ) }
import { normalizeProps, useMachine } from "@zag-js/solid" import * as timer from "@zag-js/timer" import { createMemo, createUniqueId } from "solid-js" export default function Page() { const service = useMachine(timer.machine, { id: createUniqueId(), countdown: true, autoStart: true, startMs: timer.parse({ days: 2, seconds: 10 }), }) const api = createMemo(() => timer.connect(service, normalizeProps)) return ( <div {...api().getRootProps()}> <div {...api().getAreaProps()}> <div {...api().getItemProps({ type: "days" })}> {api().formattedTime.days} </div> <div {...api().getSeparatorProps()}>:</div> <div {...api().getItemProps({ type: "hours" })}> {api().formattedTime.hours} </div> <div {...api().getSeparatorProps()}>:</div> <div {...api().getItemProps({ type: "minutes" })}> {api().formattedTime.minutes} </div> <div {...api().getSeparatorProps()}>:</div> <div {...api().getItemProps({ type: "seconds" })}> {api().formattedTime.seconds} </div> </div> <div {...api().getControlProps()}> <button {...api().getActionTriggerProps({ action: "start" })}> START </button> <button {...api().getActionTriggerProps({ action: "pause" })}> PAUSE </button> <button {...api().getActionTriggerProps({ action: "resume" })}> RESUME </button> <button {...api().getActionTriggerProps({ action: "reset" })}> RESET </button> </div> </div> ) }
<script setup lang="ts"> import * as timer from "@zag-js/timer" import { normalizeProps, useMachine } from "@zag-js/vue" import { computed } from "vue" const service = useMachine(timer.machine, { id: "v1", countdown: true, autoStart: true, startMs: timer.parse({ days: 2, seconds: 10 }), }) const api = computed(() => timer.connect(service, normalizeProps)) </script> <template> <div v-bind="api.getRootProps()"> <div v-bind="api.getAreaProps()"> <div v-bind="api.getItemProps({ type: 'days' })"> {{ api.formattedTime.days }} </div> <div v-bind="api.getSeparatorProps()">:</div> <div v-bind="api.getItemProps({ type: 'hours' })"> {{ api.formattedTime.hours }} </div> <div v-bind="api.getSeparatorProps()">:</div> <div v-bind="api.getItemProps({ type: 'minutes' })"> {{ api.formattedTime.minutes }} </div> <div v-bind="api.getSeparatorProps()">:</div> <div v-bind="api.getItemProps({ type: 'seconds' })"> {{ api.formattedTime.seconds }} </div> </div> <div v-bind="api.getControlProps()"> <button v-bind="api.getActionTriggerProps({ action: 'start' })"> START </button> <button v-bind="api.getActionTriggerProps({ action: 'pause' })"> PAUSE </button> <button v-bind="api.getActionTriggerProps({ action: 'resume' })"> RESUME </button> <button v-bind="api.getActionTriggerProps({ action: 'reset' })"> RESET </button> </div> </div> </template>
<script lang="ts"> import { normalizeProps, useMachine } from "@zag-js/svelte" import * as timer from "@zag-js/timer" const id = $props.id() const service = useMachine(timer.machine, { id, countdown: true, autoStart: true, startMs: timer.parse({ days: 2, seconds: 10 }), onComplete() { console.log("Timer completed") }, }) const api = $derived(timer.connect(service, normalizeProps)) </script> <div {...api.getRootProps()}> <div {...api.getItemProps({ type: "days" })}> {api.formattedTime.days} </div> <div {...api.getSeparatorProps()}>:</div> <div {...api.getItemProps({ type: "hours" })}> {api.formattedTime.hours} </div> <div {...api.getSeparatorProps()}>:</div> <div {...api.getItemProps({ type: "minutes" })}> {api.formattedTime.minutes} </div> <div {...api.getSeparatorProps()}>:</div> <div {...api.getItemProps({ type: "seconds" })}> {api.formattedTime.seconds} </div> </div> <div style="display: flex; gap: 4px"> <button onclick={api.start}>START</button> <button onclick={api.pause}>PAUSE</button> <button onclick={api.resume}>RESUME</button> <button onclick={api.reset}>RESET</button> </div>
Setting the start value
Set the startMs property to the timer machine's context to set the start time
in milliseconds.
const service = useMachine(timer.machine, { startMs: 1000 * 60 * 60, // 1 hour })
Alternatively, you can also use the timer.parse function to convert a date
time string or object into milliseconds
const service = useMachine(timer.machine, { startMs: timer.parse("2021-01-01T12:00:00Z"), // startMs: timer.parse({ hours: 12, minutes: 0, seconds: 0 }), })
Auto starting the timer
Set the autoStart property to true in the timer machine's context to start
the timer automatically when the component mounts.
const service = useMachine(timer.machine, { autoStart: true, })
Usage as countdown timer
To use the timer as a countdown timer, set the countdown property to true in
the timer machine's context.
const service = useMachine(timer.machine, { countdown: true, })
Setting the target value
To set the target value of the countdown timer, pass the targetMs property in
the timer machine's context. The timer stops automatically when the targetMs
is reached.
When targetMs is set and countdown=true, the timer ticks down to zero from
the specified target time.
const service = useMachine(timer.machine, { countdown: true, targetMs: 1000 * 60 * 60, // 1 hour })
When targetMs is set and countdown=false|undefined, the timer ticks up to
the specified target time.
const service = useMachine(timer.machine, { targetMs: 1000 * 60 * 60, // 1 hour })
Setting the tick interval
Set the interval property to the timer machine's context to set the tick
interval in milliseconds.
const service = useMachine(timer.machine, { interval: 1000, // 1 second })
Listening to tick events
When the timer ticks, the onTick callback is invoke. You can listen to this
event and update your UI accordingly.
const service = useMachine(timer.machine, { onTick(details) { // details => { value, segments } console.log(details) }, })
Listening for completion events
When the timer reaches the target time, the onComplete callback is invoked.
const service = useMachine(timer.machine, { countdown: true, targetMs: 1000 * 60 * 60, // 1 hour onComplete() { console.log("Timer completed") }, })
Starting and Stopping the timer
To start the timer, send the api.start() callback
api.start()
To stop the timer, send the api.stop() callback
api.stop()
Pausing and Resuming the timer
To pause the timer, send the api.pause() callback
api.pause()
To resume the timer, send the api.resume() callback
api.resume()
Methods and Properties
Machine Context
The time picker machine exposes the following context properties:
idsPartial<{ root: string; area: string; }>The ids of the timer partscountdownbooleanWhether the timer should countdown, decrementing the timer on each tick.startMsnumberThe total duration of the timer in milliseconds.targetMsnumberThe minimum count of the timer in milliseconds.autoStartbooleanWhether the timer should start automaticallyintervalnumberThe interval in milliseconds to update the timer count.onTick(details: TickDetails) => voidFunction invoked when the timer ticksonComplete() => voidFunction invoked when the timer is completedidstringThe unique identifier of the machine.getRootNode() => ShadowRoot | Node | DocumentA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.
Machine API
The time picker api exposes the following methods:
runningbooleanWhether the timer is running.pausedbooleanWhether the timer is paused.timeTime<number>The formatted timer count value.formattedTimeTime<string>The formatted time parts of the timer count.startVoidFunctionFunction to start the timer.pauseVoidFunctionFunction to pause the timer.resumeVoidFunctionFunction to resume the timer.resetVoidFunctionFunction to reset the timer.restartVoidFunctionFunction to restart the timer.progressPercentnumberThe progress percentage of the timer.
Edit this page on GitHub