Skip to main content

Command Palette

Search for a command to run...

How To Fix Framer Motion AnimatePresence Collapse Leaving a Gap

Published
2 min read
How To Fix Framer Motion AnimatePresence Collapse Leaving a Gap

Introduction

You added overflow: hidden and the collapse still looks wrong. The problem is not the motion component. It is the gap on your parent flex container.

What is happening

AnimatePresence keeps the exiting element mounted during the exit animation. It is still a flex child. Flex children still receive the parent gap even at height: 0.

You end up with an invisible ghost gap below your toggle while the panel animates out. That is the flicker.

The fix

Animate marginTop alongside height. Set it to negative the gap value on enter and exit. This cancels the gap exactly as height shrinks to zero.

// ❌ before — ghost gap remains after collapse
<motion.div
  initial={{ height: 0, opacity: 0 }}
  animate={{ height: 'auto', opacity: 1 }}
  exit={{ height: 0, opacity: 0 }}
  style={{ overflow: 'hidden' }}
>
// ✅ after — collapses cleanly
// marginTop: -40 cancels the parent gap-10 (40px) on exit
// marginTop: 0 when open — parent gap handles spacing normally
<motion.div
  initial={{ height: 0, opacity: 0, marginTop: -40 }}
  animate={{ height: 'auto', opacity: 1, marginTop: 0 }}
  exit={{ height: 0, opacity: 0, marginTop: -40 }}
  style={{ overflow: 'hidden' }}
>

Match -40 to whatever gap your parent uses.

Bonus — add blur

// blur makes the expand and collapse feel nicer and less harsh
<motion.div
  initial={{ height: 0, opacity: 0, marginTop: -40, filter: 'blur(8px)' }}
  animate={{ height: 'auto', opacity: 1, marginTop: 0, filter: 'blur(0px)' }}
  exit={{ height: 0, opacity: 0, marginTop: -40, filter: 'blur(8px)' }}
  transition={{ duration: 0.3, ease: [0.25, 0.46, 0.45, 0.94] }}
  style={{ overflow: 'hidden' }}
>

Flex gap does not care about height. A collapsed flex child is still a flex child. Animate the margin to match and the problem disappears.