Skip to main content
Version: next

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