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>)
Note you don’t even need to set 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.
Animated child components must each have a unique key prop so AnimatePresence can track their presence in the tree.
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'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