Documentation Index Fetch the complete documentation index at: https://mintlify.com/Aduwoayooluwa/animations/llms.txt
Use this file to discover all available pages before exploring further.
Live demo
Rotation animations add dynamic motion by spinning elements around their center point. They’re commonly used for loading spinners, interactive icons, and attention-grabbing effects.
Continuous rotations work best with infinite loops, while discrete rotations (90°, 180°) are great for interactive elements.
Complete code example
import { motion } from 'framer-motion'
import { useState } from 'react'
export default function RotateDemo () {
const [ rotationSpeed , setRotationSpeed ] = useState ( 2 )
return (
< div >
< label className = "block mb-4" >
Rotation Speed: { rotationSpeed } s
< input
type = "range"
min = "0.5"
max = "5"
step = "0.5"
value = { rotationSpeed }
onChange = { ( e ) => setRotationSpeed ( parseFloat ( e . target . value )) }
className = "w-full"
/>
</ label >
< motion.div
animate = { {
rotate: [ 0 , 180 , 0 ],
scale: [ 1 , 1.2 , 1 ]
} }
transition = { {
duration: rotationSpeed ,
ease: 'easeInOut' ,
repeat: Infinity ,
repeatDelay: 0.5
} }
className = "w-32 h-32 bg-blue-500 mx-auto"
/>
</ div >
)
}
import { useRef , useEffect , useState } from 'react'
import gsap from 'gsap'
export default function RotateDemo () {
const boxRef = useRef < HTMLDivElement >( null )
const [ isAnimating , setIsAnimating ] = useState ( false )
const startRotation = () => {
if ( ! boxRef . current ) return
setIsAnimating ( true )
gsap . to ( boxRef . current , {
rotation: 360 ,
duration: 2 ,
ease: 'linear' ,
repeat: - 1
})
}
const stopRotation = () => {
if ( ! boxRef . current ) return
gsap . killTweensOf ( boxRef . current )
setIsAnimating ( false )
}
return (
< div >
< div
ref = { boxRef }
className = "w-32 h-32 bg-green-500 mx-auto mb-4"
/>
< button
onClick = { isAnimating ? stopRotation : startRotation }
className = "px-4 py-2 bg-green-500 text-white rounded"
>
{ isAnimating ? 'Stop' : 'Start' } Rotation
</ button >
</ div >
)
}
import './rotate.css'
export default function RotateDemo () {
return (
< div className = "flex flex-col items-center gap-8" >
< div className = "rotate-continuous w-32 h-32 bg-purple-500" />
< div className = "rotate-discrete w-32 h-32 bg-pink-500" />
</ div >
)
}
@keyframes rotate {
0% { transform : rotate ( 0 deg ); }
100% { transform : rotate ( 360 deg ); }
}
@keyframes rotate-discrete {
0% , 100% { transform : rotate ( 0 deg ); }
50% { transform : rotate ( 180 deg ); }
}
.rotate-continuous {
animation : rotate 3 s linear infinite ;
}
.rotate-discrete {
animation : rotate-discrete 2 s ease-in-out infinite ;
}
How it works
Rotation animations use the CSS rotate or transform: rotate() property:
Set rotation angle
Define the target rotation in degrees (0-360°) or radians.
Choose timing function
Use linear for continuous spins or ease-in-out for smoother starts/stops.
Set repeat behavior
Decide if the animation should loop infinitely or play once.
Rotation types
Continuous spin 360° rotation with linear timing, infinite repeat. Perfect for loading indicators.
Discrete rotation Fixed angle rotations (90°, 180°) with easing. Great for interactive elements.
Wobble rotation Back-and-forth rotation using negative values. Creates attention-grabbing effect.
Combined rotation Rotation combined with other transforms like scale or translate.
Variations
Loading spinner
Classic loading indicator with rotation:
import { motion } from 'framer-motion'
function LoadingSpinner () {
return (
< motion.div
animate = { { rotate: 360 } }
transition = { {
duration: 1 ,
repeat: Infinity ,
ease: 'linear'
} }
className = "w-12 h-12 border-4 border-blue-500 border-t-transparent rounded-full"
/>
)
}
Rotate on hover
Interactive rotation triggered by hover:
import { motion } from 'framer-motion'
function RotateOnHover () {
return (
< motion.button
whileHover = { { rotate: 180 } }
transition = { { duration: 0.3 } }
className = "p-4 bg-blue-500 text-white rounded-lg"
>
Hover Me
</ motion.button >
)
}
3D rotation
Rotate on multiple axes for 3D effect:
import { motion } from 'framer-motion'
function Rotate3D () {
return (
< motion.div
animate = { {
rotateY: [ 0 , 360 ],
rotateX: [ 0 , 180 , 0 ]
} }
transition = { {
duration: 3 ,
repeat: Infinity ,
ease: 'easeInOut'
} }
style = { { transformStyle: 'preserve-3d' } }
className = "w-32 h-32 bg-gradient-to-r from-purple-500 to-pink-500"
/>
)
}
Wobble effect
Back-and-forth rotation for attention:
< motion.div
animate = { { rotate: [ - 5 , 5 , - 5 ] } }
transition = { {
duration: 0.5 ,
repeat: Infinity ,
repeatType: 'reverse'
} }
>
Notification Badge
</ motion.div >
Example from the playground
This code is extracted from the Animation Playground’s ReactAnimations component:
import { motion } from 'framer-motion'
import { useState } from 'react'
function RotationPlayground () {
const [ rotationSpeed , setRotationSpeed ] = useState ( 2 )
const [ scaleAmount , setScaleAmount ] = useState ( 1.2 )
return (
< div >
< div className = "flex gap-4 mb-4" >
< label >
Rotation Speed: { rotationSpeed } s
< input
type = "range"
min = "0.5"
max = "5"
step = "0.5"
value = { rotationSpeed }
onChange = { ( e ) => setRotationSpeed ( parseFloat ( e . target . value )) }
/>
</ label >
< label >
Scale: { scaleAmount } x
< input
type = "range"
min = "1"
max = "2"
step = "0.1"
value = { scaleAmount }
onChange = { ( e ) => setScaleAmount ( parseFloat ( e . target . value )) }
/>
</ label >
</ div >
< motion.div
animate = { {
scale: [ 1 , scaleAmount , 1 ],
rotate: [ 0 , 180 , 0 ],
borderRadius: [ '0%' , '50%' , '0%' ]
} }
transition = { {
duration: rotationSpeed ,
ease: 'easeInOut' ,
repeat: Infinity ,
repeatDelay: 0.5
} }
className = "w-32 h-32 bg-blue-500 mx-auto cursor-pointer"
whileHover = { { scale: 1.1 } }
whileTap = { { scale: 0.9 } }
/>
</ div >
)
}
Best practices
Choose appropriate easing
linear: Continuous, mechanical rotations
ease-in-out: Natural starts and stops
spring: Bouncy, playful rotations
Too much rotation can cause motion sickness. Use sparingly and respect prefers-reduced-motion.
Combine with other transforms
Rotation works great with scale and translate for more dynamic animations.
Common use cases
Loading spinners and progress indicators
Refresh/reload buttons
Expand/collapse icons (chevrons)
Animated logos
Card flips
Gear/cog animations
Success/error indicators
Rotation using transform: rotate() is GPU-accelerated. Avoid using deprecated rotation properties.
// Good - GPU accelerated
< motion.div animate = { { rotate: 360 } } />
// Also good - 3D rotation
< motion.div animate = { { rotateY: 360 } } />
// Avoid - not standard
< motion.div style = { { rotation: 360 } } />
Scale Grow and shrink animations
Bounce Bouncing motion effects
Morph Shape transformations