Component
Countdown Widget
Use this widget (code component) on your Framer website to add a customizable countdown element to it. This can be used for product launches, limited time offers, and more.
Created by
About the resource
Fully customizable through component properties.
You can:
Change font size.
Change text color.
Specify font family & weight.
Toggle days, hours, minutes, and seconds.
Specify an end date.
Specify an end message.
Source code
If you want to take a look at how such a code component is built in Framer, feel free to copy this code from below and dig into it.
About the resource
Fully customizable through component properties.
You can:
Change font size.
Change text color.
Specify font family & weight.
Toggle days, hours, minutes, and seconds.
Specify an end date.
Specify an end message.
Source code
If you want to take a look at how such a code component is built in Framer, feel free to copy this code from below and dig into it.
About the resource
Fully customizable through component properties.
You can:
Change font size.
Change text color.
Specify font family & weight.
Toggle days, hours, minutes, and seconds.
Specify an end date.
Specify an end message.
Source code
If you want to take a look at how such a code component is built in Framer, feel free to copy this code from below and dig into it.
import React, { useState, useEffect } from "react"
import { addPropertyControls, ControlType } from "framer"
export default function Countdown({
fontSize,
fontFamily,
fontColor,
fontWeight,
displayDays,
displayHours,
displayMinutes,
displaySeconds,
endDate,
endTime,
endMessage,
}) {
const [timeLeft, setTimeLeft] = useState(calculateTimeLeft())
useEffect(() => {
const timer = setTimeout(() => {
setTimeLeft(calculateTimeLeft())
}, 1000)
return () => clearTimeout(timer)
})
function calculateTimeLeft() {
const difference = +new Date(`${endDate}T${endTime}`) - +new Date()
let timeLeft = {}
if (difference > 0) {
if (difference < 60 * 60 * 1000) {
// Less than 60 minutes remaining
const minutes = Math.floor((difference / (1000 * 60)) % 60)
const seconds = Math.floor((difference / 1000) % 60)
timeLeft = {
days: displayDays ? 0 : null,
hours: displayHours ? 0 : null,
minutes: displayMinutes ? minutes : null,
seconds: displaySeconds ? seconds : null,
}
} else {
const time = {
d: Math.floor(difference / (1000 * 60 * 60 * 24)),
h: Math.floor((difference / (1000 * 60 * 60)) % 24),
m: Math.floor((difference / (1000 * 60)) % 60),
s: Math.floor((difference / 1000) % 60),
}
timeLeft = {
days: displayDays ? time.d : 0,
hours: displayHours ? time.h : null,
minutes: displayMinutes ? time.m : null,
seconds: displaySeconds ? time.s : null,
}
}
}
return timeLeft
}
const timerComponents = []
Object.keys(timeLeft).forEach((interval) => {
if (!timeLeft[interval]) {
return
}
timerComponents.push(
<span
key={interval}
style={{
display: "flex",
alignItems: "center",
flexDirection: "column",
}}
>
{timeLeft[interval]}
<span style={{ fontSize: `${fontSize / 2.5}px` }}>
{interval.toLowerCase()}
</span>
</span>
)
})
return (
<div
style={{
fontSize,
fontFamily,
color: fontColor,
fontWeight,
display: "flex",
gap: "20px",
}}
>
{timerComponents.length ? (
timerComponents
) : (
<span>{endMessage}</span>
)}
</div>
)
}
addPropertyControls(Countdown, {
fontSize: {
type: ControlType.Number,
unit: "px",
defaultValue: 30,
},
fontFamily: {
type: ControlType.String,
defaultValue: "Inter",
},
fontColor: {
type: ControlType.Color,
defaultValue: "black",
},
fontWeight: {
type: ControlType.Enum,
defaultValue: 400,
options: [
"normal",
"bold",
"bolder",
"lighter",
100,
200,
300,
400,
500,
600,
700,
800,
900,
],
},
displayDays: {
type: ControlType.Boolean,
defaultValue: true,
},
displayHours: {
type: ControlType.Boolean,
defaultValue: true,
},
displayMinutes: {
type: ControlType.Boolean,
defaultValue: true,
},
displaySeconds: {
type: ControlType.Boolean,
defaultValue: true,
},
endDate: {
type: ControlType.String,
defaultValue: "2023-04-25",
description: "YYYY-MM-DD",
},
endTime: {
type: ControlType.String,
defaultValue: "00:00:00",
description: "HH:MM:SS",
},
endMessage: {
type: ControlType.String,
defaultValue: "Time's up!",
},
})
import React, { useState, useEffect } from "react"
import { addPropertyControls, ControlType } from "framer"
export default function Countdown({
fontSize,
fontFamily,
fontColor,
fontWeight,
displayDays,
displayHours,
displayMinutes,
displaySeconds,
endDate,
endTime,
endMessage,
}) {
const [timeLeft, setTimeLeft] = useState(calculateTimeLeft())
useEffect(() => {
const timer = setTimeout(() => {
setTimeLeft(calculateTimeLeft())
}, 1000)
return () => clearTimeout(timer)
})
function calculateTimeLeft() {
const difference = +new Date(`${endDate}T${endTime}`) - +new Date()
let timeLeft = {}
if (difference > 0) {
if (difference < 60 * 60 * 1000) {
// Less than 60 minutes remaining
const minutes = Math.floor((difference / (1000 * 60)) % 60)
const seconds = Math.floor((difference / 1000) % 60)
timeLeft = {
days: displayDays ? 0 : null,
hours: displayHours ? 0 : null,
minutes: displayMinutes ? minutes : null,
seconds: displaySeconds ? seconds : null,
}
} else {
const time = {
d: Math.floor(difference / (1000 * 60 * 60 * 24)),
h: Math.floor((difference / (1000 * 60 * 60)) % 24),
m: Math.floor((difference / (1000 * 60)) % 60),
s: Math.floor((difference / 1000) % 60),
}
timeLeft = {
days: displayDays ? time.d : 0,
hours: displayHours ? time.h : null,
minutes: displayMinutes ? time.m : null,
seconds: displaySeconds ? time.s : null,
}
}
}
return timeLeft
}
const timerComponents = []
Object.keys(timeLeft).forEach((interval) => {
if (!timeLeft[interval]) {
return
}
timerComponents.push(
<span
key={interval}
style={{
display: "flex",
alignItems: "center",
flexDirection: "column",
}}
>
{timeLeft[interval]}
<span style={{ fontSize: `${fontSize / 2.5}px` }}>
{interval.toLowerCase()}
</span>
</span>
)
})
return (
<div
style={{
fontSize,
fontFamily,
color: fontColor,
fontWeight,
display: "flex",
gap: "20px",
}}
>
{timerComponents.length ? (
timerComponents
) : (
<span>{endMessage}</span>
)}
</div>
)
}
addPropertyControls(Countdown, {
fontSize: {
type: ControlType.Number,
unit: "px",
defaultValue: 30,
},
fontFamily: {
type: ControlType.String,
defaultValue: "Inter",
},
fontColor: {
type: ControlType.Color,
defaultValue: "black",
},
fontWeight: {
type: ControlType.Enum,
defaultValue: 400,
options: [
"normal",
"bold",
"bolder",
"lighter",
100,
200,
300,
400,
500,
600,
700,
800,
900,
],
},
displayDays: {
type: ControlType.Boolean,
defaultValue: true,
},
displayHours: {
type: ControlType.Boolean,
defaultValue: true,
},
displayMinutes: {
type: ControlType.Boolean,
defaultValue: true,
},
displaySeconds: {
type: ControlType.Boolean,
defaultValue: true,
},
endDate: {
type: ControlType.String,
defaultValue: "2023-04-25",
description: "YYYY-MM-DD",
},
endTime: {
type: ControlType.String,
defaultValue: "00:00:00",
description: "HH:MM:SS",
},
endMessage: {
type: ControlType.String,
defaultValue: "Time's up!",
},
})
import React, { useState, useEffect } from "react"
import { addPropertyControls, ControlType } from "framer"
export default function Countdown({
fontSize,
fontFamily,
fontColor,
fontWeight,
displayDays,
displayHours,
displayMinutes,
displaySeconds,
endDate,
endTime,
endMessage,
}) {
const [timeLeft, setTimeLeft] = useState(calculateTimeLeft())
useEffect(() => {
const timer = setTimeout(() => {
setTimeLeft(calculateTimeLeft())
}, 1000)
return () => clearTimeout(timer)
})
function calculateTimeLeft() {
const difference = +new Date(`${endDate}T${endTime}`) - +new Date()
let timeLeft = {}
if (difference > 0) {
if (difference < 60 * 60 * 1000) {
// Less than 60 minutes remaining
const minutes = Math.floor((difference / (1000 * 60)) % 60)
const seconds = Math.floor((difference / 1000) % 60)
timeLeft = {
days: displayDays ? 0 : null,
hours: displayHours ? 0 : null,
minutes: displayMinutes ? minutes : null,
seconds: displaySeconds ? seconds : null,
}
} else {
const time = {
d: Math.floor(difference / (1000 * 60 * 60 * 24)),
h: Math.floor((difference / (1000 * 60 * 60)) % 24),
m: Math.floor((difference / (1000 * 60)) % 60),
s: Math.floor((difference / 1000) % 60),
}
timeLeft = {
days: displayDays ? time.d : 0,
hours: displayHours ? time.h : null,
minutes: displayMinutes ? time.m : null,
seconds: displaySeconds ? time.s : null,
}
}
}
return timeLeft
}
const timerComponents = []
Object.keys(timeLeft).forEach((interval) => {
if (!timeLeft[interval]) {
return
}
timerComponents.push(
<span
key={interval}
style={{
display: "flex",
alignItems: "center",
flexDirection: "column",
}}
>
{timeLeft[interval]}
<span style={{ fontSize: `${fontSize / 2.5}px` }}>
{interval.toLowerCase()}
</span>
</span>
)
})
return (
<div
style={{
fontSize,
fontFamily,
color: fontColor,
fontWeight,
display: "flex",
gap: "20px",
}}
>
{timerComponents.length ? (
timerComponents
) : (
<span>{endMessage}</span>
)}
</div>
)
}
addPropertyControls(Countdown, {
fontSize: {
type: ControlType.Number,
unit: "px",
defaultValue: 30,
},
fontFamily: {
type: ControlType.String,
defaultValue: "Inter",
},
fontColor: {
type: ControlType.Color,
defaultValue: "black",
},
fontWeight: {
type: ControlType.Enum,
defaultValue: 400,
options: [
"normal",
"bold",
"bolder",
"lighter",
100,
200,
300,
400,
500,
600,
700,
800,
900,
],
},
displayDays: {
type: ControlType.Boolean,
defaultValue: true,
},
displayHours: {
type: ControlType.Boolean,
defaultValue: true,
},
displayMinutes: {
type: ControlType.Boolean,
defaultValue: true,
},
displaySeconds: {
type: ControlType.Boolean,
defaultValue: true,
},
endDate: {
type: ControlType.String,
defaultValue: "2023-04-25",
description: "YYYY-MM-DD",
},
endTime: {
type: ControlType.String,
defaultValue: "00:00:00",
description: "HH:MM:SS",
},
endMessage: {
type: ControlType.String,
defaultValue: "Time's up!",
},
})