Countdown

A countdown animation.

Preview

Code

Code

app/page.tsx

1import Countdown from "@/components/countdown"; 2 3const Home = () => { 4 return ( 5 <div className=" bg-[#F3F3F3] h-screen flex items-center justify-center"> 6 <Countdown /> 7 </div> 8 ); 9} 10 11export default Home;

Installation

Initialized a project and installed the necessary dependencies to use this component.

1. Initialize a new Next.js project:

Code
npx create-next-app@latest my-app

2. Install Framer Motion

Code
npm install framer-motion

Add Countdown Component

Code

src/components/countdown.tsx

1"use client"; 2 3import { AnimatePresence, motion } from "framer-motion"; 4import { useEffect, useRef, useState } from "react"; 5 6// NOTE: Change this date to whatever date you want to countdown to 7const COUNTDOWN_FROM = "04/21/2026"; 8 9const SECOND = 1000; 10const MINUTE = SECOND * 60; 11const HOUR = MINUTE * 60; 12const DAY = HOUR * 24; 13 14const Countdown = () => { 15 const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null); 16 17 const [remaining, setRemaining] = useState({ 18 days: 0, 19 hours: 0, 20 minutes: 0, 21 seconds: 0, 22 }); 23 24 useEffect(() => { 25 intervalRef.current = setInterval(handleCountdown, 1000); 26 27 return () => clearInterval(intervalRef.current || undefined); 28 }, []); 29 30 const handleCountdown = () => { 31 const end = new Date(COUNTDOWN_FROM); 32 33 const now = new Date(); 34 35 const distance = +end - +now; 36 37 const days = Math.floor(distance / DAY); 38 const hours = Math.floor((distance % DAY) / HOUR); 39 const minutes = Math.floor((distance % HOUR) / MINUTE); 40 const seconds = Math.floor((distance % MINUTE) / SECOND); 41 42 setRemaining({ 43 days, 44 hours, 45 minutes, 46 seconds, 47 }); 48 }; 49 50 return ( 51 <div> 52 <div className="py-2 px-4 bg-white/70 text-black shadow-sm backdrop-blur-md border border-[#DADADA] rounded-full"> 53 <div className="w-full max-w-5xl -mt-4 mx-auto flex items-center rounded-full gap-0"> 54 <CountdownItem unit="days" num={remaining.days} /> 55 <p className="mx-2 font-semibold text-lg -mt-2">:</p> 56 <CountdownItem unit="hours" num={remaining.hours} /> 57 <p className="mx-2 font-semibold text-lg -mt-2">:</p> 58 <CountdownItem unit="minutes" num={remaining.minutes} /> 59 <p className="mx-2 font-semibold text-lg -mt-2">:</p> 60 <CountdownItem unit="seconds" num={remaining.seconds} /> 61 </div> 62 </div> 63 </div> 64 ); 65}; 66 67const CountdownItem = ({ num, unit }: { num: number; unit: string }) => { 68 return ( 69 <div className=" flex flex-col items-center"> 70 <div className=" aspect-square rounded-full w-16 h-16 flex flex-col gap-1 md:gap-0 items-center justify-center"> 71 <div className="w-full text-center relative overflow-hidden"> 72 <AnimatePresence mode="popLayout"> 73 <motion.span 74 key={num} 75 initial={{ y: "100%" }} 76 animate={{ y: "0%" }} 77 exit={{ y: "-100%" }} 78 transition={{ ease: "backIn", duration: 0.75 }} 79 className="block text-lg md:text-2xl font-semibold" 80 > 81 {num} 82 </motion.span> 83 </AnimatePresence> 84 </div> 85 </div> 86 <p className=" -mt-5 opacity-70">{unit}</p> 87 </div> 88 ); 89}; 90 91export default Countdown;

Become an Astrae
Affiliate Today

Make referrals, and bring in clients. Keep 50% of your earnings paid out weekly.

Description