Presence Basics
Conditional rendering ({isOpen && <div>...}) removes elements from the DOM
instantly, so there's no chance to animate them out. Presence keeps an
exiting child mounted until its exit animation finishes, then removes it.
Usage
import { Presence, animate, withTiming, withSpring } from 'react-ui-animate';
function Toggle() {
const [isVisible, setIsVisible] = useState(true);
return (
<>
<button onClick={() => setIsVisible((v) => !v)}>Toggle</button>
{/* Presence keeps the child mounted until exit finishes */}
<Presence>
{isVisible && (
<animate.div
animate={{ opacity: withSpring(1), scale: withSpring(1) }}
exit={{ opacity: withTiming(0), scale: withSpring(0.85) }}
style={{ opacity: 0, scale: 0.85, width: 100, height: 100 }}
/>
)}
</Presence>
</>
);
}
Preview
note
Each direct child of Presence needs a unique key if there's more than
one (e.g. a modal's backdrop + panel). That's how Presence tracks which
child is entering/exiting across renders.
<Presence>
{isOpen && (
/* Unique keys let Presence track each exiting child */
<>
<animate.div key="backdrop" exit={{ opacity: withTiming(0) }} />
<animate.div key="panel" exit={{ opacity: withTiming(0), scale: withSpring(0.9) }} />
</>
)}
</Presence>
Enter + exit together
animate (mount) and exit (unmount) compose on the same element: mount
target in animate, leave target in exit, and keep the initial hidden
values in style.
Next steps
- The animate Component: the
animate/exitprops themselves. - usePresence & useIsPresent: drive an exit animation
manually instead of via the
exitprop. - recipes: ready-made
exitFade/exitSlideUp/etc. values for theexitprop.