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:
npx create-next-app@latest my-app
2. Install Framer Motion
npm install framer-motion
Add Countdown Component
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;