loading circles
A fun loading indicator using 8 circles
> COMPONENTS:
> motion.div
> useAnimate
> spring
> KEYWORDS:
loadingloadertranslatecirclerotatespinner
> SOURCE CODE:
"use client"
import { AnimationSequence, DOMSegmentWithTransition, motion, useAnimate } from "motion/react"
import { useEffect } from "react"
const NUMBER_OF_CIRCLES = 8
const LoadingCircles = () => {
const [scope, animate] = useAnimate()
useEffect(() => {
const radius = 100
const timeline: AnimationSequence = [
...Array.from(Array(NUMBER_OF_CIRCLES)).map((circle, index) => {
// Calculate the angle in radians, starting at -90° (12 o'clock)
const angle = ((-90 + (360 / NUMBER_OF_CIRCLES) * index) * Math.PI) / 180
const x = radius * Math.cos(angle)
const y = radius * Math.sin(angle)
const transition: DOMSegmentWithTransition = [".circle-"+index, { x, y }, { duration: 0.2 }]
return transition
}),
['.circle-wrapper', { rotate: 360 }, { duration: 2.2, type: 'spring' }],
...Array.from(Array(NUMBER_OF_CIRCLES)).map((circle, index) => {
const transition: DOMSegmentWithTransition = [".circle-"+index, { x: 0, y: 0 }, { duration: 0.2 }]
return transition
}),
]
animate(timeline, { repeat: Infinity })
}, [scope, animate])
return (
<div className="w-40 h-40" ref={scope}>
<motion.div className="w-full h-full flex items-center justify-center relative circle-wrapper">
<div className="w-10 h-10 rounded-full bg-amber-500 absolute" />
{Array.from(Array(NUMBER_OF_CIRCLES)).map((circle, index) => (
<motion.div
className={"w-10 h-10 rounded-full bg-amber-500 absolute circle-"+index}
key={index}
/>
))}
</motion.div>
</div>
)
}
export default LoadingCircles