AnimatePresence
Animate components as they mount and unmount
AnimatePresence animates direct children before they unmount. It is inspired by and forked from Framer Motion , but works with any animation driver in Tamagui.
To use with @tamagui/core, install and import @tamagui/animate-presence. It’s already bundled and exported from tamagui.
Basic Usage
Use enterStyle and exitStyle to define how components animate in and out:
import { AnimatePresence, View } from 'tamagui'export const MyComponent = ({ isVisible }) => (<AnimatePresence>{isVisible && (<View key="my-square" transition="bouncy" backgroundColor="green" size={50} enterStyle={{ opacity: 0, y: 10, scale: 0.9, }} exitStyle={{ opacity: 0, y: -10, scale: 0.9, }} />)}</AnimatePresence>)
opacity on the base style. Tamagui knows to normalize
styles like opacity and scale to 1 (and y to 0) if it’s not defined on the base styles
but is defined on enterStyle or exitStyle.Wrap one or more Tamagui components with AnimatePresence. The child components will animate on enter and exit.
Enter/Exit Transitions
You can specify different animations for enter (mount) and exit (unmount) transitions. This is useful when you want elements to enter slowly but exit quickly, or vice versa:
import { AnimatePresence, View } from 'tamagui'export default ({ show }) => (<AnimatePresence>{show && (<View key="panel" transition={{ enter: 'lazy', exit: 'quick' }} enterStyle={{ opacity: 0, y: 20 }} exitStyle={{ opacity: 0, y: -20 }} />)}</AnimatePresence>)
The enter and exit keys accept any animation name from your config. You can also combine them with a default for property changes that happen while the element is mounted:
// enter slowly, exit quickly, property changes use medium speed<View transition={{ enter: 'lazy', exit: 'quick', default: 'bouncy' }} enterStyle={{ opacity: 0 }} exitStyle={{ opacity: 0 }} />
Or use enter/exit with the array syntax to include delay and per-property animations:
// enter with lazy, exit with quick, delay 200ms, x uses its own animation<View transition={['bouncy', { enter: 'lazy', exit: 'quick', delay: 200, x: 'slow' }]} enterStyle={{ opacity: 0, x: -100 }} exitStyle={{ opacity: 0, x: 100 }} />
This works with all four animation drivers (CSS, React Native, Reanimated, Motion).
The custom prop

AnimatePresence takes a custom prop that allows you to update a variant of the animated child before it runs its exit animation. This is useful for animating a child out of the screen in a different direction before it unmounts, as shown in the example above:
import { AnimatePresence } from '@tamagui/animate-presence'import { ArrowLeft, ArrowRight } from '@tamagui/lucide-icons-2'import { useState } from 'react'import { Button, Image, XStack, YStack, styled } from 'tamagui'const GalleryItem = styled(YStack, {zIndex: 1,x: 0,opacity: 1,fullscreen: true,variants: {// 1 = right, 0 = nowhere, -1 = leftgoing: {':number': (going) => ({enterStyle: {x: going > 0 ? 1000 : -1000,opacity: 0,},exitStyle: {zIndex: 0,x: going < 0 ? 1000 : -1000,opacity: 0,},}),},} as const,})const photos = ['https://picsum.photos/500/300','https://picsum.photos/501/300','https://picsum.photos/502/300',]const wrap = (min: number, max: number, v: number) => {const rangeSize = max - minreturn ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min}export function Demo() {const [[page, going], setPage] = useState([0, 0])const imageIndex = wrap(0, photos.length, page)const paginate = (going: number) => {setPage([page + going, going])}return (<XStack overflow="hidden" backgroundColor="#000" position="relative" height={300} width="100%" alignItems="center" ><AnimatePresence initial={false} custom={{ going }}><GalleryItem key={page} transition="slowest" going={going}><Image src={photos[imageIndex]} width={500} height={300} /></GalleryItem></AnimatePresence><Button accessibilityLabel="Carousel left" icon={ArrowLeft} size="$5" position="absolute" left="$4" circular elevate onPress={() => paginate(-1)} zi={100} /><Button accessibilityLabel="Carousel right" icon={ArrowRight} size="$5" position="absolute" right="$4" circular elevate onPress={() => paginate(1)} zi={100} /></XStack>)}
API Reference
AnimatePresence Props
children- One or more Tamagui components with uniquekeypropsinitial- Iffalse, children entering on initial mount won’t animate (default:true)custom- Pass data to children’s variants for dynamic exit animationsexitBeforeEnter- Iftrue, only one child renders at a time (default:false)onExitComplete- Callback fired when all exiting children have finished animating
Component Props
When used inside AnimatePresence:
enterStyle- Styles to animate from when mountingexitStyle- Styles to animate to when unmountingtransition- Animation configuration (can use{ enter, exit }syntax)key- Required unique identifier for AnimatePresence tracking