Timer
Measure elapsed or remaining time with start, pause, and reset actions.
Usage
Stopwatch
Start, pause, resume, and reset elapsed time with controls that reflect the current state.
<!-- Timer / Stopwatch -->
<script setup lang="ts">
import { TimerActionTrigger, TimerArea, TimerItem, TimerRoot, TimerSeparator } from '@sectile/vue/timer'
</script>
<template>
<TimerRoot v-slot="{ running, valueMs }">
<TimerArea><TimerItem type="minutes" /><TimerSeparator>:</TimerSeparator><TimerItem type="seconds" /></TimerArea>
<TimerActionTrigger v-if="running" action="pause">Pause</TimerActionTrigger>
<TimerActionTrigger v-else-if="valueMs > 0" action="resume">Resume</TimerActionTrigger>
<TimerActionTrigger v-else action="start">Start timer</TimerActionTrigger>
<TimerActionTrigger v-if="valueMs > 0" action="reset">Reset</TimerActionTrigger>
</TimerRoot>
</template>Countdown
Set a duration, track remaining time, and receive completion feedback.
<!-- Timer / Countdown -->
<script setup lang="ts">
import { computed, ref } from 'vue'
import { NumberField } from '@sectile/vue/number-field'
import { TimerActionTrigger, TimerArea, TimerItem, TimerRoot, TimerSeparator } from '@sectile/vue/timer'
const seconds = ref('10')
const durationMs = computed(() => Math.max(1, Number(seconds.value)) * 1_000)
const timerKey = ref(0)
const autoStart = ref(false)
function applyDuration() { autoStart.value = true; timerKey.value += 1 }
</script>
<template>
<label>Seconds <NumberField v-model="seconds" :policies="{ min: '1' }" /></label>
<button @click="applyDuration">Apply & start</button>
<TimerRoot :key="timerKey" countdown :start-ms="durationMs" :auto-start="autoStart"
v-slot="{ running, completed, progress, valueMs }">
<TimerArea><TimerItem type="minutes" /><TimerSeparator>:</TimerSeparator><TimerItem type="seconds" /></TimerArea>
<progress :value="progress ?? 0" max="100" />
<p v-if="completed" role="status">Focus session finished.</p>
<TimerActionTrigger v-if="running" action="pause">Pause</TimerActionTrigger>
<TimerActionTrigger v-else-if="valueMs < durationMs" action="resume">Resume</TimerActionTrigger>
<TimerActionTrigger v-else action="start">Start</TimerActionTrigger>
<TimerActionTrigger action="reset">Reset</TimerActionTrigger>
</TimerRoot>
</template>Target
Set an elapsed-time goal and track progress until completion.
<!-- Timer / Target -->
<script setup lang="ts">
import { computed, ref } from 'vue'
import { NumberField } from '@sectile/vue/number-field'
import { TimerActionTrigger, TimerArea, TimerItem, TimerRoot, TimerSeparator } from '@sectile/vue/timer'
const targetSeconds = ref('15')
const targetMs = computed(() => Math.max(1, Number(targetSeconds.value)) * 1_000)
const timerKey = ref(0)
function applyTarget() { timerKey.value += 1 }
</script>
<template>
<label>Target seconds <NumberField v-model="targetSeconds" :policies="{ min: '1' }" /></label>
<button @click="applyTarget">Apply target</button>
<TimerRoot :key="timerKey" :target-ms="targetMs" v-slot="{ running, completed, progress, valueMs }">
<TimerArea><TimerItem type="minutes" /><TimerSeparator>:</TimerSeparator><TimerItem type="seconds" /></TimerArea>
<progress :value="progress ?? 0" max="100" />
<p v-if="completed" role="status">Target reached.</p>
<TimerActionTrigger v-if="running" action="pause">Pause</TimerActionTrigger>
<TimerActionTrigger v-else-if="valueMs > 0" action="resume">Resume</TimerActionTrigger>
<TimerActionTrigger v-else action="start">Start</TimerActionTrigger>
<TimerActionTrigger action="reset">Reset</TimerActionTrigger>
</TimerRoot>
</template>API
Vue package: @sectile/vue/timer
TimerRootTimerAreaTimerSeparatorTimerControlTimerItemTimerActionTrigger
Props
TimerRootProps
asElement or component rendered for this part.
asChildWhether to merge this part into its single child instead of rendering a wrapper.
autoStartWhether the timer starts immediately after mounting.
countdownWhether the timer counts down instead of measuring elapsed time.
intervalMsDelay in milliseconds between automatic updates.
startMsInitial elapsed time in milliseconds.
targetMsElapsed-time target in milliseconds.
TimerPartProps
asElement or component rendered for this part.
asChildWhether to merge this part into its single child instead of rendering a wrapper.
Slots
TimerSlotProps
completedWhether the timer reached its target.
partsFormatted segments of the current value.
pausePauses timer updates.
progressCompletion progress from 0 to 1.
resetRestores the initial value and interaction state.
restartRestarts timing from the configured initial value.
resumeResumes a paused timer.
runningWhether the timer is currently running.
startStarts timer updates.
valueMsCurrent timer value in milliseconds.
Events
TimerRoot
completeEmitted when every required segment is filled.
tickEmitted when a timer interval produces a new value.
Other types
TimerTickHandler
type TimerTickHandler = (valueMs: number) => voidTimerCompleteHandler
type TimerCompleteHandler = (valueMs: number) => voidParts
Shared scope: [data-scope="timer"]. Combine it with a part selector to keep styles local to this component.
| Part | Selector | Role | Extra attributes |
|---|---|---|---|
root | [data-part="root"] | Defines the component boundary and owns its composed parts. | — |
area | [data-part="area"] | Provides the two-dimensional interaction surface. | — |
item | [data-part="item"] | Represents one selectable or actionable item. | — |
separator | [data-part="separator"] | Separates related groups without becoming an action. | — |
control | [data-part="control"] | Groups the primary interactive controls. | — |
action-trigger | [data-part="action-trigger"] | Invokes a timer action. | — |
Keyboard interaction
| Key | Behavior |
|---|---|
| Tab | Move between the component's native action controls. |
| Enter / Space | Invoke the focused action. |
Accessibility
Formatted time parts are grouped as one value while start, pause, reset, and restart remain named actions.
