Building a Countdown Component for Vue with Composables
In this tutorial, we'll build a simple countdown component for Vue using composable functions. We'll start by creating
a useCountdown
composable that calculates the time left until a specified future date, and then we'll use this
composable in a Countdown
component to display the remaining time in hours, minutes, and seconds — like this:
CREATING THE useCountdown
COMPOSABLE
Our useCountdown
composable function will take a futureDate
parameter and return an object containing the time left
until that date. To accomplish this, we'll first define an interface for our TimeLeft
object that contains a Ref
for
each unit of time we want to display:
import { Ref } from "@vue/runtime-core"
interface TimeLeft {
seconds: Ref<number>
minutes: Ref<number>
hours: Ref<number>
days: Ref<number>
months: Ref<number>
years: Ref<number>
}
Next, we'll define our useCountdown function, which will create a timeLeft object containing the Refs defined above. It will then start a setInterval timer that calls a calculateTimeLeft function every second to update the timeLeft object. If the remaining time is less than 0, we'll stop the timer using clearInterval and return the timeLeft object.
export function useCountdown(futureDate: Date): {
timeLeft: TimeLeft,
clearCountdown: Function
} {
const timeLeft: TimeLeft = ( {
seconds: ref(0),
minutes: ref(0),
hours: ref(0),
days: ref(0),
months: ref(0),
years: ref(0)
} )
let interval: string | number | NodeJS.Timer | undefined
const clearCountdown = () => {
clearInterval(interval)
}
const calculateTimeLeft = () => {
const timeRemaining = Date.parse(futureDate.toString()) - Date.now()
if (timeRemaining < 0) {
clearCountdown()
return timeLeft
}
timeLeft.seconds.value = Math.floor(( timeRemaining / 1000 ) % 60)
timeLeft.minutes.value = Math.floor(( timeRemaining / 1000 / 60 ) % 60)
timeLeft.hours.value = Math.floor(( timeRemaining / ( 1000 * 60 * 60 ) ) % 24)
timeLeft.days.value = Math.floor(timeRemaining / ( 1000 * 60 * 60 * 24 ))
timeLeft.months.value = Math.floor(timeLeft.days.value / 30)
timeLeft.years.value = Math.floor(timeLeft.months.value / 12)
return timeLeft
}
interval = setInterval(calculateTimeLeft, 1000)
calculateTimeLeft()
return {
timeLeft,
clearCountdown
}
}
BUILDING THE Countdown
COMPONENT
Now that we have our useCountdown
composable function, we can use it in a Countdown
component to display the
remaining time until a specified date. We'll create a futureDate
variable to hold the date we're counting down to, and
then call useCountdown
with that variable to create a countdown to that date and time.
We'll use the onUnmounted
lifecycle hook to call clearCountdown
when the component is unmounted to avoid memory
leaks.
Finally, we render the remaining time along with the countdown end date using simple HTML and CSS. You can customize the styles of the component by modifying the CSS in the style section.
<script lang="ts" setup>
import { useCountdown } from "~/composables/useCountdown"
let futureDate = new Date()
futureDate.setTime(futureDate.getTime() + ( 60 * 60 * 24 * 1000 ))
const {timeLeft, clearCountdown} = useCountdown(futureDate)
const {hours, minutes, seconds, days, years} = timeLeft
onUnmounted(() => {
clearCountdown()
})
</script>
<template>
<div class="countdown">
<div class="countdown__remaining">
{{ hours }}h {{ minutes }}m {{ seconds }}s
</div>
<div class="countdown__until">
until
</div>
<div class="countdown__date">{{ futureDate.toLocaleString() }}</div>
</div>
</template>
<style lang="scss" scoped>
.countdown {
text-align: center;
margin-top: 1rem;
margin-bottom: 1rem;
&__remaining {
font-weight: bold;
font-size: 2rem;
}
&__until {
text-transform: uppercase;
margin: .25rem auto;
}
&__date {
font-size: 1.5rem;
}
}
</style>
All done!
In this tutorial, we've built a countdown component for Vue using composable functions. We started by creating a useCountdown composable that calculates the time left until a specified future date, and then we used this composable in a Countdown component to display the remaining time in hours, minutes, and seconds.
By using composable functions, we were able to separate the logic for calculating the time left from the presentation of the countdown component, making our code more modular and easier to maintain.
I hope this tutorial has been helpful in demonstrating the power of composable functions in Vue, and how they can simplify complex logic in your components. If you have any questions or feedback, please feel free to leave a comment below.