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
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 [state, send] = useMachine( timer.machine({ id: useId(), countdown: true, autoStart: true, startMs: timer.parse({ days: 2, seconds: 10 }), }), ) const api = timer.connect(state, send, 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 [state, send] = useMachine( timer.machine({ id: createUniqueId(), countdown: true, autoStart: true, startMs: timer.parse({ days: 2, seconds: 10 }), }), ) const api = createMemo(() => timer.connect(state, send, 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 [state, send] = useMachine( timer.machine({ id: "v1", countdown: true, autoStart: true, startMs: timer.parse({ days: 2, seconds: 10 }), }), ) const api = computed(() => timer.connect(state.value, send, 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>
Setting the start value
Set the startMs property to the timer machine's context to set the start time
in milliseconds.
const [state, send] = 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 [state, send] = 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 [state, send] = 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 [state, send] = 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 [state, send] = 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 [state, send] = 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 [state, send] = 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 [state, send] = 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 [state, send] = 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.start() => voidFunction to start the timer.pause() => voidFunction to pause the timer.resume() => voidFunction to resume the timer.reset() => voidFunction to reset the timer.restart() => voidFunction to restart the timer.progressPercentnumberThe progress percentage of the timer.
Edit this page on GitHub