Skip to content

Instantly share code, notes, and snippets.

@nandorojo
Last active March 5, 2024 13:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nandorojo/c7c97f9a6baf3b3db4e55ae8b9699ba4 to your computer and use it in GitHub Desktop.
Save nandorojo/c7c97f9a6baf3b3db4e55ae8b9699ba4 to your computer and use it in GitHub Desktop.
LayoutView: Moti + Framer Motion + React Native (+ Web)

Simply put, layout animations differ in React Native and React Native Web.

This gist is a simple approach to let you use one component to power layout animations across both platforms.

<LayoutView>
  <Text>Lay me out</Text>
</LayoutView>

You can use the layout prop to pass true, false, or a framer motion value. You can also pass reanimated Layout here (which will be the default, unless you pass layout={false}.

<LayoutView layout="size" layoutId="indicator">
  <View />
</LayoutView>

You can also use layoutId, although this will only work on Web. On Native, you'd need to use the component's key and ensure that the component stays in the same place in the tree.

import { MotiView } from 'moti'
import { styled } from 'dripsy'
import { LayoutViewProps } from './types'
import { Layout } from 'react-native-reanimated'
const LayoutView = ({ state, layout, ...props }: LayoutViewProps) => (
<MotiView
state={state}
layout={
layout === false
? undefined
: typeof layout == 'string' || layout === true
? Layout.duration(200)
: layout
}
{...props}
/>
)
export { LayoutView }
import { unstable_createElement } from 'react-native-web'
import { motion } from 'framer-motion'
import type { LayoutViewProps } from './types'
/**
* @deprecated wrong import
* we write this to prevent importing this file, since you should always import from index
*/
const LayoutView = ({ layout = true, ...props }: LayoutViewProps) => {
return unstable_createElement(motion.div, {
layout: typeof layout == 'string' ? layout : Boolean(layout),
...props,
})
}
LayoutView.displayName = 'LayoutView'
export { LayoutView }
import type { motion } from 'framer-motion'
import type { MotiView } from 'moti'
import type { ComponentProps } from 'react'
import type Animated from 'react-native-reanimated'
export type LayoutViewProps = {
children?: React.ReactNode
layout?: ComponentProps<typeof Animated.View | typeof motion.div>['layout']
} & Pick<ComponentProps<typeof motion.div>, 'layoutId'> &
Pick<ComponentProps<typeof MotiView>, 'state'>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment