Live demo
Slide animations move elements into view from a specific direction, creating a sense of spatial awareness and directionality. They’re perfect for navigation menus, sidebars, and sequential content reveals.
Combine slide animations with fade effects for smoother, more polished transitions.
Complete code example
Framer Motion
React Spring
CSS
import { motion } from 'framer-motion'
import { useState } from 'react'
export default function SlideInDemo () {
const [ direction , setDirection ] = useState < 'left' | 'right' | 'top' | 'bottom' >( 'left' )
const variants = {
left: { x: - 100 , opacity: 0 },
right: { x: 100 , opacity: 0 },
top: { y: - 100 , opacity: 0 },
bottom: { y: 100 , opacity: 0 },
}
return (
< div >
< div className = "flex gap-2 mb-4" >
{ ([ 'left' , 'right' , 'top' , 'bottom' ] as const ). map (( dir ) => (
< button
key = { dir }
onClick = { () => setDirection ( dir ) }
className = "px-3 py-1 bg-blue-500 text-white rounded"
>
{ dir }
</ button >
)) }
</ div >
< motion.div
key = { direction }
initial = { variants [ direction ] }
animate = { { x: 0 , y: 0 , opacity: 1 } }
transition = { { type: 'spring' , damping: 25 , stiffness: 300 } }
className = "p-6 bg-gradient-to-r from-purple-500 to-pink-500 text-white rounded-lg"
>
Sliding from { direction }
</ motion.div >
</ div >
)
}
import { useSpring , animated } from '@react-spring/web'
import { useState } from 'react'
export default function SlideInDemo () {
const [ direction , setDirection ] = useState ( 'left' )
const slideProps = useSpring ({
from: {
transform: direction === 'left' ? 'translateX(-100px)' : 'translateX(100px)' ,
opacity: 0
},
to: {
transform: 'translateX(0px)' ,
opacity: 1
},
config: { tension: 300 , friction: 25 }
})
return (
< div >
< div className = "flex gap-2 mb-4" >
< button onClick = { () => setDirection ( 'left' ) } > From Left </ button >
< button onClick = { () => setDirection ( 'right' ) } > From Right </ button >
</ div >
< animated.div
style = { {
... slideProps ,
padding: '1.5rem' ,
background: 'linear-gradient(to right, #8B5CF6, #EC4899)' ,
color: 'white' ,
borderRadius: '0.5rem'
} }
>
Sliding with spring physics
</ animated.div >
</ div >
)
}
import { useState } from 'react'
import './slide.css'
export default function SlideInDemo () {
const [ key , setKey ] = useState ( 0 )
return (
< div >
< button
onClick = { () => setKey ( k => k + 1 ) }
className = "mb-4 px-4 py-2 bg-blue-500 text-white rounded"
>
Replay Animation
</ button >
< div
key = { key }
className = "slide-in-left p-6 bg-gradient-to-r from-purple-500 to-pink-500 text-white rounded-lg"
>
Sliding with CSS
</ div >
</ div >
)
}
@keyframes slide-in-left {
0% {
transform : translateX ( -100 % );
opacity : 0 ;
}
100% {
transform : translateX ( 0 );
opacity : 1 ;
}
}
@keyframes slide-in-right {
0% {
transform : translateX ( 100 % );
opacity : 0 ;
}
100% {
transform : translateX ( 0 );
opacity : 1 ;
}
}
.slide-in-left {
animation : slide-in-left 0.5 s ease-out ;
}
.slide-in-right {
animation : slide-in-right 0.5 s ease-out ;
}
How it works
Slide animations use transform properties to move elements:
Initial position
Place the element off-screen or offset from its final position using translateX or translateY.
Animate to final
Transition the transform to translate(0) to slide the element into its natural position.
Add opacity
Combine with opacity changes (0 to 1) for a smoother, more polished effect.
Direction reference
From left translateX(-100%) or x: -100
From right translateX(100%) or x: 100
From top translateY(-100%) or y: -100
From bottom translateY(100%) or y: 100
Variations
Common pattern for navigation menus:
import { motion , AnimatePresence } from 'framer-motion'
function Sidebar ({ isOpen , onClose }) {
return (
< AnimatePresence >
{ isOpen && (
<>
{ /* Backdrop */ }
< motion.div
initial = { { opacity: 0 } }
animate = { { opacity: 1 } }
exit = { { opacity: 0 } }
onClick = { onClose }
className = "fixed inset-0 bg-black/50 z-40"
/>
{ /* Sidebar */ }
< motion.div
initial = { { x: - 300 } }
animate = { { x: 0 } }
exit = { { x: - 300 } }
transition = { { type: 'spring' , damping: 30 , stiffness: 300 } }
className = "fixed left-0 top-0 bottom-0 w-64 bg-white shadow-xl z-50"
>
Sidebar content
</ motion.div >
</>
) }
</ AnimatePresence >
)
}
Sequential slide in
Slide in items one after another:
import { motion } from 'framer-motion'
const container = {
hidden: {},
show: {
transition: {
staggerChildren: 0.1
}
}
}
const item = {
hidden: { x: - 50 , opacity: 0 },
show: { x: 0 , opacity: 1 }
}
function SequentialSlide ({ items }) {
return (
< motion.div
variants = { container }
initial = "hidden"
animate = "show"
>
{ items . map (( text , i ) => (
< motion.div
key = { i }
variants = { item }
className = "p-4 mb-2 bg-gray-100 rounded"
>
{ text }
</ motion.div >
)) }
</ motion.div >
)
}
Slide and rotate
Add rotation for dynamic effect:
< motion.div
initial = { { x: - 100 , opacity: 0 , rotate: - 10 } }
animate = { { x: 0 , opacity: 1 , rotate: 0 } }
transition = { { type: 'spring' , stiffness: 200 } }
>
Content
</ motion.div >
Best practices
Slide direction should match the user’s mental model:
Navigation from left for LTR languages
Modals from bottom on mobile
Notifications from top or corner
Spring-based transitions feel more natural than linear ones for slide animations. // Good
transition = {{ type : 'spring' , damping : 25 }}
// Less natural
transition = {{ duration : 0.3 , ease : 'linear' }}
Add backdrop for overlays
When sliding in panels or sidebars, include a semi-transparent backdrop.
On mobile, allow users to swipe to dismiss slide-in panels.
Common use cases
Navigation drawers and sidebars
Mobile menu overlays
Notification panels
Image carousels
Wizard steps
Chat messages
Always use transform: translate() instead of left/right/top/bottom for animations. Transform is GPU-accelerated and won’t trigger layout recalculations.
// Good - GPU accelerated
< motion.div animate = { { x: 0 } } />
// Bad - Causes layout thrashing
< motion.div animate = { { left: 0 } } />
Fade in Opacity-based transitions
Drag gesture Swipeable interactions
Morph Shape transformations