# Timer

URL: https://ark-ui.com/docs/components/timer
Source: https://raw.githubusercontent.com/chakra-ui/ark/refs/heads/main/website/src/content/pages/components/timer.mdx

Used to record the time elapsed from zero or since a specified target time.

---

<ComponentPreview id="Timer" />

## Anatomy

<Anatomy id="timer" />

```tsx
<Timer.Root>
  <Timer.Area>
    <Timer.Item />
    <Timer.Separator />
  </Timer.Area>
  <Timer.Control>
    <Timer.ActionTrigger />
  </Timer.Control>
</Timer.Root>
```

## Examples

**Example: basic**

```ripple
import { Timer } from 'ark-ripple/timer';
import { Pause, Play } from 'lucide-ripple';
import button from 'styles/button.module.css';
import styles from 'styles/timer.module.css';

export component Basic() {
  <Timer.Root class="stack" targetMs={60 * 60 * 1000} startMs={40 * 60 * 1000}>
    <Timer.Area class={styles.Area}>
      <div class={styles.ItemGroup}>
        <Timer.Item class={styles.Item} type="days" />
        <span class={styles.ItemLabel}>{'days'}</span>
      </div>
      <Timer.Separator class={styles.Separator}>{':'}</Timer.Separator>
      <div class={styles.ItemGroup}>
        <Timer.Item class={styles.Item} type="hours" />
        <span class={styles.ItemLabel}>{'hours'}</span>
      </div>
      <Timer.Separator class={styles.Separator}>{':'}</Timer.Separator>
      <div class={styles.ItemGroup}>
        <Timer.Item class={styles.Item} type="minutes" />
        <span class={styles.ItemLabel}>{'minutes'}</span>
      </div>
      <Timer.Separator class={styles.Separator}>{':'}</Timer.Separator>
      <div class={styles.ItemGroup}>
        <Timer.Item class={styles.Item} type="seconds" />
        <span class={styles.ItemLabel}>{'seconds'}</span>
      </div>
    </Timer.Area>
    <Timer.Control class="hstack">
      <Timer.ActionTrigger class={button.Root} action="start">
        <Play />
        {'Play'}
      </Timer.ActionTrigger>
      <Timer.ActionTrigger class={button.Root} action="resume">
        <Play />
        {'Resume'}
      </Timer.ActionTrigger>
      <Timer.ActionTrigger class={button.Root} action="pause">
        <Pause />
        {'Pause'}
      </Timer.ActionTrigger>
    </Timer.Control>
  </Timer.Root>
}

```

### Countdown

You can create a countdown timer by setting the `countdown` prop to `true` and `startMs` to the initial time:

**Example: countdown**

```ripple
import { Timer } from 'ark-ripple/timer';
import { Pause, Play, RotateCcw } from 'lucide-ripple';
import button from 'styles/button.module.css';
import styles from 'styles/timer.module.css';

export component Countdown() {
  <Timer.Root class="stack" countdown startMs={5 * 60 * 1000}>
    <Timer.Area class={styles.Area}>
      <div class={styles.ItemGroup}>
        <Timer.Item class={styles.Item} type="minutes" />
        <span class={styles.ItemLabel}>{'minutes'}</span>
      </div>
      <Timer.Separator class={styles.Separator}>{':'}</Timer.Separator>
      <div class={styles.ItemGroup}>
        <Timer.Item class={styles.Item} type="seconds" />
        <span class={styles.ItemLabel}>{'seconds'}</span>
      </div>
    </Timer.Area>
    <Timer.Control class="hstack">
      <Timer.ActionTrigger class={button.Root} action="start">
        <Play />
        {'Start'}
      </Timer.ActionTrigger>
      <Timer.ActionTrigger class={button.Root} action="pause">
        <Pause />
        {'Pause'}
      </Timer.ActionTrigger>
      <Timer.ActionTrigger class={button.Root} action="reset">
        <RotateCcw />
        {'Reset'}
      </Timer.ActionTrigger>
    </Timer.Control>
  </Timer.Root>
}

```

### Interval

Use the `interval` prop to control how frequently the timer updates. This is useful for displaying milliseconds:

**Example: interval**

```ripple
import { Timer } from 'ark-ripple/timer';
import { Pause, Play, RotateCcw } from 'lucide-ripple';
import button from 'styles/button.module.css';
import styles from 'styles/timer.module.css';

export component Interval() {
  <Timer.Root class="stack" interval={100} targetMs={60 * 1000}>
    <Timer.Area class={styles.Area}>
      <div class={styles.ItemGroup}>
        <Timer.Item class={styles.Item} type="seconds" />
        <span class={styles.ItemLabel}>{'seconds'}</span>
      </div>
      <Timer.Separator class={styles.Separator}>{'.'}</Timer.Separator>
      <div class={styles.ItemGroup}>
        <Timer.Item class={styles.Item} type="milliseconds" />
        <span class={styles.ItemLabel}>{'ms'}</span>
      </div>
    </Timer.Area>
    <Timer.Control class="hstack">
      <Timer.ActionTrigger class={button.Root} action="start">
        <Play />
        {'Start'}
      </Timer.ActionTrigger>
      <Timer.ActionTrigger class={button.Root} action="pause">
        <Pause />
        {'Pause'}
      </Timer.ActionTrigger>
      <Timer.ActionTrigger class={button.Root} action="reset">
        <RotateCcw />
        {'Reset'}
      </Timer.ActionTrigger>
    </Timer.Control>
  </Timer.Root>
}

```

### Events

The Timer component provides events that you can listen to for various timer-related actions.

- The `onComplete` event is triggered when the timer reaches its target time.
- The `onTick` event is called on each timer update, providing details about the current timer state.

**Example: events**

```ripple
import { Timer } from 'ark-ripple/timer';
import { Play, RotateCcw } from 'lucide-ripple';
import { track } from 'ripple';
import button from 'styles/button.module.css';
import styles from 'styles/timer.module.css';

export component Events() {
  let ticks = track(0);

  <Timer.Root
    class="stack"
    targetMs={60 * 1000}
    onComplete={() => {
      console.log('Timer completed');
    }}
    onTick={() => {
      @ticks = @ticks + 1;
    }}
  >
    <Timer.Area class={styles.Area}>
      <div class={styles.ItemGroup}>
        <Timer.Item class={styles.Item} type="minutes" />
        <span class={styles.ItemLabel}>{'minutes'}</span>
      </div>
      <Timer.Separator class={styles.Separator}>{':'}</Timer.Separator>
      <div class={styles.ItemGroup}>
        <Timer.Item class={styles.Item} type="seconds" />
        <span class={styles.ItemLabel}>{'seconds'}</span>
      </div>
    </Timer.Area>

    <Timer.Control class="hstack">
      <Timer.ActionTrigger class={button.Root} action="start">
        <Play />
        {'Start'}
      </Timer.ActionTrigger>
      <Timer.ActionTrigger class={button.Root} action="reset">
        <RotateCcw />
        {'Reset'}
      </Timer.ActionTrigger>
    </Timer.Control>

    <output>
      {'Ticks: '}
      {@ticks}
    </output>
  </Timer.Root>
}

```

### Pomodoro

Here's an example of building a pomodoro timer that alternates between work and break sessions:

**Example: pomodoro**

```ripple
import { Timer } from 'ark-ripple/timer';
import { Pause, Play, RotateCcw } from 'lucide-ripple';
import { track } from 'ripple';
import button from 'styles/button.module.css';
import styles from 'styles/timer.module.css';

export component Pomodoro() {
  let isWorking = track(true);
  let cycles = track(0);

  const handleComplete = () => {
    @isWorking = !@isWorking;
    if (!@isWorking) {
      @cycles = @cycles + 1;
    }
  };

  <Timer.Root
    class="stack"
    startMs={@isWorking ? 25 * 60 * 1000 : 5 * 60 * 1000}
    countdown
    onComplete={handleComplete}
  >
    <h2>{@isWorking ? 'Work Session' : 'Break Session'}</h2>

    <Timer.Area class={styles.Area}>
      <div class={styles.ItemGroup}>
        <Timer.Item class={styles.Item} type="minutes" />
        <span class={styles.ItemLabel}>{'minutes'}</span>
      </div>
      <Timer.Separator class={styles.Separator}>{':'}</Timer.Separator>
      <div class={styles.ItemGroup}>
        <Timer.Item class={styles.Item} type="seconds" />
        <span class={styles.ItemLabel}>{'seconds'}</span>
      </div>
    </Timer.Area>

    <Timer.Control class="hstack">
      <Timer.ActionTrigger class={button.Root} action="start">
        <Play />
        {'Start'}
      </Timer.ActionTrigger>
      <Timer.ActionTrigger class={button.Root} action="pause">
        <Pause />
        {'Pause'}
      </Timer.ActionTrigger>
      <Timer.ActionTrigger class={button.Root} action="reset">
        <RotateCcw />
        {'Reset'}
      </Timer.ActionTrigger>
    </Timer.Control>

    <output>
      {'Completed cycles: '}
      {@cycles}
    </output>
  </Timer.Root>
}

```

### Root Provider

An alternative way to control the timer is to use the `RootProvider` component and the `useTimer` hook. This way you can
access the state and methods from outside the component.

**Example: root-provider**

```ripple
import { Timer, useTimer } from 'ark-ripple/timer';
import { Pause, Play, RotateCcw } from 'lucide-ripple';
import button from 'styles/button.module.css';
import styles from 'styles/timer.module.css';

export component RootProvider() {
  const timer = useTimer({ targetMs: 60 * 60 * 1000 });

  <div class="stack">
    <output>
      {'timer: '}
      {JSON.stringify(@timer.time)}
    </output>
    <Timer.RootProvider class={styles.Root} value={timer}>
      <Timer.Area class={styles.Area}>
        <div class={styles.ItemGroup}>
          <Timer.Item class={styles.Item} type="hours" />
          <span class={styles.ItemLabel}>{'hours'}</span>
        </div>
        <Timer.Separator class={styles.Separator}>{':'}</Timer.Separator>
        <div class={styles.ItemGroup}>
          <Timer.Item class={styles.Item} type="minutes" />
          <span class={styles.ItemLabel}>{'minutes'}</span>
        </div>
        <Timer.Separator class={styles.Separator}>{':'}</Timer.Separator>
        <div class={styles.ItemGroup}>
          <Timer.Item class={styles.Item} type="seconds" />
          <span class={styles.ItemLabel}>{'seconds'}</span>
        </div>
      </Timer.Area>
      <Timer.Control class="hstack">
        <Timer.ActionTrigger class={button.Root} action="start">
          <Play />
          {'Start'}
        </Timer.ActionTrigger>
        <Timer.ActionTrigger class={button.Root} action="resume">
          <Play />
          {'Resume'}
        </Timer.ActionTrigger>
        <Timer.ActionTrigger class={button.Root} action="pause">
          <Pause />
          {'Pause'}
        </Timer.ActionTrigger>
        <Timer.ActionTrigger class={button.Root} action="reset">
          <RotateCcw />
          {'Reset'}
        </Timer.ActionTrigger>
      </Timer.Control>
    </Timer.RootProvider>
  </div>
}

```

## API Reference

### Props

**Component API Reference**

**Root Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| `autoStart` | `boolean` | No | Whether the timer should start automatically |
| `countdown` | `boolean` | No | Whether the timer should countdown, decrementing the timer on each tick. |
| `ids` | `Partial<{ root: string; area: string }>` | No | The ids of the timer parts |
| `interval` | `number` | No | The interval in milliseconds to update the timer count. |
| `onComplete` | `() => void` | No | Function invoked when the timer is completed |
| `onTick` | `(details: TickDetails) => void` | No | Function invoked when the timer ticks |
| `startMs` | `number` | No | The total duration of the timer in milliseconds. |
| `targetMs` | `number` | No | The minimum count of the timer in milliseconds. |


**ActionTrigger Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `action` | `TimerAction` | Yes |  |
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**Area Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**Control Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**Item Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `type` | `keyof Time<number>` | Yes |  |
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**Item Data Attributes:**

| Attribute | Value |
|-----------|-------|
| `[data-scope]` | timer |
| `[data-part]` | item |
| `[data-type]` | The type of the item |


**Item CSS Variables:**

| Variable | Description |
|----------|-------------|
| `--value` | The current value |


**RootProvider Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `value` | `UseTimerReturn` | Yes |  |
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**Separator Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


### Context

**API:**

| Property | Type | Description |
|----------|------|-------------|
| `running` | `boolean` | Whether the timer is running. |
| `paused` | `boolean` | Whether the timer is paused. |
| `time` | `Time<number>` | The formatted timer count value. |
| `formattedTime` | `Time<string>` | The formatted time parts of the timer count. |
| `start` | `VoidFunction` | Function to start the timer. |
| `pause` | `VoidFunction` | Function to pause the timer. |
| `resume` | `VoidFunction` | Function to resume the timer. |
| `reset` | `VoidFunction` | Function to reset the timer. |
| `restart` | `VoidFunction` | Function to restart the timer. |
| `progressPercent` | `number` | The progress percentage of the timer. |
