Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 64 additions & 10 deletions versioned_docs/version-6.x/shared-element-transitions.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
# Animating elements between screens

This guide covers how to animate elements between screens. This feature is known as a [Shared Element Transition](https://docs.swmansion.com/react-native-reanimated/docs/api/sharedElementTransitions) and it's implemented in the [`@react-navigation/native-stack`](/docs/native-stack-navigator) with [React Native Reanimated](https://docs.swmansion.com/react-native-reanimated/).
This guide covers how to animate elements between screens. This feature is known as a [Shared Element Transition](https://docs.swmansion.com/react-native-reanimated/docs/shared-element-transitions/overview/) and it's implemented in the [`@react-navigation/native-stack`](native-stack-navigator.md) with [React Native Reanimated](https://docs.swmansion.com/react-native-reanimated/).

:::warning

As of writing this guide, Shared Element Transitions are considered an experimental feature not recommended for production use.
Shared Element Transitions are an experimental feature not recommended for production use yet.

**Architecture support:**

- **Reanimated 3** supports Shared Element Transitions on the **Old Architecture** (Paper).
- **Reanimated 4** supports them on the **New Architecture** (Fabric) since **4.2.0**, but the feature is behind a feature flag. You need to [enable the `ENABLE_SHARED_ELEMENT_TRANSITIONS` feature flag](https://docs.swmansion.com/react-native-reanimated/docs/guides/feature-flags#enable_shared_element_transitions) to use it.

Check [the Reanimated documentation](https://docs.swmansion.com/react-native-reanimated/docs/shared-element-transitions/overview/) for details and [send feedback to the Reanimated team](https://github.com/software-mansion/react-native-reanimated)

:::

Expand All @@ -16,8 +23,9 @@ As of writing this guide, Shared Element Transitions are considered an experimen

Before continuing this guide make sure your app meets these criteria:

- You are using [`@react-navigation/native-stack`](native-stack-navigator.md). The Shared Element Transitions feature isn't supported in JS-based [`@react-navigation/stack`](stack-navigator.md).
- You are using [`@react-navigation/native-stack`](native-stack-navigator.md). JS-based [`@react-navigation/stack`](stack-navigator.md) or other navigators are not supported.
- You have [`react-native-reanimated`](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/getting-started) **v3.0.0 or higher** installed and configured.
- If you are using **Reanimated 4** (New Architecture), you must [enable the `ENABLE_SHARED_ELEMENT_TRANSITIONS` feature flag](https://docs.swmansion.com/react-native-reanimated/docs/guides/feature-flags#enable_shared_element_transitions).

## Minimal example

Expand Down Expand Up @@ -92,28 +100,29 @@ const styles = StyleSheet.create({

## Customizing the transition

By default, the transition animates the `width`, `height`, `originX`, `originY` and `transform` properties using `withTiming` with a 500 ms duration. You can easily customize `width`, `height`, `originX`, and `originY` props. Customizing `transform` is also possible but it's far beyond the scope of this guide.
You can customize the transition by passing a custom `SharedTransition` configuration via the `sharedTransitionStyle` prop. Apply the same `sharedTransitionStyle` to the matching element on the target screen.

:::warning
Custom transition configuration is not fully finalized and might change in a future release.

Custom SharedTransition API is not finalized and might change in a future release.
### Old Architecture (Reanimated 3)

:::

To customize the transition you need to pass all the properties besides `transform`.
By default, the transition animates `width`, `height`, `originX`, `originY`, and `transform` using `withTiming` with a 500 ms duration. You can customize the transition using `SharedTransition.custom()`:

```jsx
import { SharedTransition } from 'react-native-reanimated';
import { SharedTransition, withSpring } from 'react-native-reanimated';

// highlight-start
const customTransition = SharedTransition.custom((values) => {
'worklet';

return {
height: withSpring(values.targetHeight),
width: withSpring(values.targetWidth),
originX: withSpring(values.targetOriginX),
originY: withSpring(values.targetOriginY),
};
});
// highlight-end

function HomeScreen() {
return (
Expand All @@ -127,10 +136,55 @@ function HomeScreen() {
}
```

### New Architecture (Reanimated 4)

On the New Architecture, the default transition animates `width`, `height`, `originX`, `originY`, `transform`, `backgroundColor`, and `opacity` using `withTiming` with a 500 ms duration.

Currently customization is more limited due to ongoing development. You can't define fully custom animation functions. Instead, use the `SharedTransition` builder class to configure duration and spring-based animations:

```jsx
import { SharedTransition } from 'react-native-reanimated';

// Customize duration and use spring animation
// highlight-next-line
const customTransition = SharedTransition.duration(550).springify();

function HomeScreen() {
return (
<Animated.Image
style={{ width: 300, height: 300 }}
sharedTransitionTag="tag"
// highlight-next-line
sharedTransitionStyle={customTransition}
/>
);
}
```

## Reference

You can find a full Shared Element Transitions reference in the [React Native Reanimated documentation](https://docs.swmansion.com/react-native-reanimated/docs/shared-element-transitions/overview/).

## Limitations

Shared Element Transitions currently have several limitations to be aware of:

- Only the [native stack navigator](native-stack-navigator.md) is supported
- Other navigators such as JS stack, drawer, and bottom tabs are not supported
- Transitions with native modals don't work properly on iOS

### New Architecture specific limitations (Reanimated 4)

The following limitations apply specifically when using Reanimated 4 on the New Architecture:

- The feature must be enabled via the `ENABLE_SHARED_ELEMENT_TRANSITIONS` feature flag
- Custom animation functions are not supported; you can only customize duration and use spring-based animations
- Some properties (e.g., `backgroundColor`) are not supported in progress-based transitions (iOS back gesture)
- There are performance bottlenecks with transforms being recalculated too eagerly
- On iOS, you may encounter issues with vertical positioning due to header height information propagation

The limitations will be addressed in future Reanimated releases.

## Alternatives

Alternatively, you can use [`react-native-shared-element`](https://github.com/IjzerenHein/react-native-shared-element) library with a [React Navigation binding](https://github.com/IjzerenHein/react-navigation-shared-element) which implements Shared Element Transitions in a JS-based `@react-navigation/stack` navigator. This solution, however, isn't actively maintained.
Expand Down
152 changes: 61 additions & 91 deletions versioned_docs/version-7.x/shared-element-transitions.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@ This guide covers how to animate elements between screens. This feature is known

:::warning

As of writing this guide, Shared Element Transitions are considered an experimental feature not recommended for production use.
Shared Element Transitions are an experimental feature not recommended for production use yet.

Shared Element Transitions are currently only supported on **old React Native architecture** (Paper).
**Architecture support:**

- **Reanimated 3** supports Shared Element Transitions on the **Old Architecture** (Paper).
- **Reanimated 4** supports them on the **New Architecture** (Fabric) since **4.2.0**, but the feature is behind a feature flag. You need to [enable the `ENABLE_SHARED_ELEMENT_TRANSITIONS` feature flag](https://docs.swmansion.com/react-native-reanimated/docs/guides/feature-flags#enable_shared_element_transitions) to use it.

Check [the Reanimated documentation](https://docs.swmansion.com/react-native-reanimated/docs/shared-element-transitions/overview/) for details and [send feedback to the Reanimated team](https://github.com/software-mansion/react-native-reanimated)

:::

Expand All @@ -25,8 +30,9 @@ Shared Element Transitions are currently only supported on **old React Native ar

Before continuing this guide make sure your app meets these criteria:

- You are using [`@react-navigation/native-stack`](native-stack-navigator.md). The Shared Element Transitions feature isn't supported in JS-based [`@react-navigation/stack`](stack-navigator.md).
- You are using [`@react-navigation/native-stack`](native-stack-navigator.md). JS-based [`@react-navigation/stack`](stack-navigator.md) or other navigators are not supported.
- You have [`react-native-reanimated`](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/getting-started) **v3.0.0 or higher** installed and configured.
- If you are using **Reanimated 4** (New Architecture), you must [enable the `ENABLE_SHARED_ELEMENT_TRANSITIONS` feature flag](https://docs.swmansion.com/react-native-reanimated/docs/guides/feature-flags#enable_shared_element_transitions).

## Minimal example

Expand All @@ -36,10 +42,7 @@ To create a shared transition:
2. Assign the same `sharedTransitionTag` to elements on different screens.
3. Navigate between screens. The transition will start automatically.

<Tabs groupId="config" queryString="config">
<TabItem value="static" label="Static" default>

```js name="Shared transition"
```js static2dynamic name="Shared transition"
import * as React from 'react';
import { View, StyleSheet } from 'react-native';
import {
Expand Down Expand Up @@ -85,14 +88,12 @@ function DetailsScreen() {
);
}

// highlight-start
const RootStack = createNativeStackNavigator({
screens: {
Home: HomeScreen,
Details: DetailsScreen,
},
});
// highlight-end

const Navigation = createStaticNavigation(RootStack);

Expand All @@ -108,111 +109,66 @@ const styles = StyleSheet.create({
});
```

</TabItem>
<TabItem value="dynamic" label="Dynamic">

```js name="Shared transition"
import * as React from 'react';
import { View, StyleSheet } from 'react-native';
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';

import Animated from 'react-native-reanimated';

// highlight-next-line
const Stack = createNativeStackNavigator();

function HomeScreen() {
const navigation = useNavigation();

return (
<View style={styles.container}>
<Button onPress={() => navigation.navigate('Details')}>
Go to Details
</Button>
<Animated.Image
source={{ uri: 'https://picsum.photos/id/39/200' }}
style={{ width: 300, height: 300 }}
// highlight-next-line
sharedTransitionTag="tag"
/>
</View>
);
}

function DetailsScreen() {
const navigation = useNavigation();

return (
<View style={styles.container}>
<Button onPress={() => navigation.goBack()}>Go back</Button>
<Animated.Image
source={{ uri: 'https://picsum.photos/id/39/200' }}
style={{ width: 100, height: 100 }}
// highlight-next-line
sharedTransitionTag="tag"
/>
</View>
);
}

export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
},
});
```

</TabItem>
</Tabs>

`sharedTransitionTag` is a string that has to be unique in the context of a single screen, but has to match elements between screens. This prop allows Reanimated to identify and animate the elements, similarly to the [`key`](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key) property, which tells React which element in the list is which.

## Customizing the transition

By default, the transition animates the `width`, `height`, `originX`, `originY` and `transform` properties using `withTiming` with a 500 ms duration. You can easily customize `width`, `height`, `originX`, and `originY` props. Customizing `transform` is also possible but it's far beyond the scope of this guide.
You can customize the transition by passing a custom `SharedTransition` configuration via the `sharedTransitionStyle` prop. Apply the same `sharedTransitionStyle` to the matching element on the target screen.

:::warning
Custom transition configuration is not fully finalized and might change in a future release.

Custom SharedTransition API is not finalized and might change in a future release.
### Old Architecture (Reanimated 3)

:::

To customize the transition you need to pass all the properties besides `transform`.
By default, the transition animates `width`, `height`, `originX`, `originY`, and `transform` using `withTiming` with a 500 ms duration. You can customize the transition using `SharedTransition.custom()`:

```jsx
import { SharedTransition } from 'react-native-reanimated';
import { SharedTransition, withSpring } from 'react-native-reanimated';

// highlight-start
const customTransition = SharedTransition.custom((values) => {
'worklet';

return {
height: withSpring(values.targetHeight),
width: withSpring(values.targetWidth),
originX: withSpring(values.targetOriginX),
originY: withSpring(values.targetOriginY),
};
});
// highlight-end

function HomeScreen() {
return (
<Animated.Image
style={{ width: 300, height: 300 }}
sharedTransitionTag="tag"
// highlight-next-line
sharedTransitionStyle={customTransition} // add this to both elements on both screens
sharedTransitionStyle={customTransition}
/>
);
}
```

### New Architecture (Reanimated 4)

On the New Architecture, the default transition animates `width`, `height`, `originX`, `originY`, `transform`, `backgroundColor`, and `opacity` using `withTiming` with a 500 ms duration.

Currently customization is more limited due to ongoing development. You can't define fully custom animation functions. Instead, use the `SharedTransition` builder class to configure duration and spring-based animations:

```jsx
import { SharedTransition } from 'react-native-reanimated';

// Customize duration and use spring animation
// highlight-next-line
const customTransition = SharedTransition.duration(550).springify();

function HomeScreen() {
return (
<Animated.Image
style={{ width: 300, height: 300 }}
sharedTransitionTag="tag"
// highlight-next-line
sharedTransitionStyle={customTransition}
/>
);
}
Expand All @@ -222,8 +178,22 @@ function HomeScreen() {

You can find a full Shared Element Transitions reference in the [React Native Reanimated documentation](https://docs.swmansion.com/react-native-reanimated/docs/shared-element-transitions/overview/).

## Alternatives
## Limitations

Shared Element Transitions currently have several limitations to be aware of:

- Only the [native stack navigator](native-stack-navigator.md) is supported
- Other navigators such as JS stack, drawer, and bottom tabs are not supported
- Transitions with native modals don't work properly on iOS

### New Architecture specific limitations (Reanimated 4)

The following limitations apply specifically when using Reanimated 4 on the New Architecture:

Alternatively, you can use [`react-native-shared-element`](https://github.com/IjzerenHein/react-native-shared-element) library with a [React Navigation binding](https://github.com/IjzerenHein/react-navigation-shared-element) which implements Shared Element Transitions in a JS-based `@react-navigation/stack` navigator. This solution, however, isn't actively maintained.
- The feature must be enabled via the `ENABLE_SHARED_ELEMENT_TRANSITIONS` feature flag
- Custom animation functions are not supported; you can only customize duration and use spring-based animations
- Some properties (e.g., `backgroundColor`) are not supported in progress-based transitions (iOS back gesture)
- There are performance bottlenecks with transforms being recalculated too eagerly
- On iOS, you may encounter issues with vertical positioning due to header height information propagation

The [`react-native-navigation`](https://github.com/wix/react-native-navigation) also comes with support for Shared Element Transitions. You can read more about it [here](https://wix.github.io/react-native-navigation/docs/style-animations#shared-element-transitions).
The limitations will be addressed in future Reanimated releases.
Loading