diff --git a/src/content/reference/react/ViewTransition.md b/src/content/reference/react/ViewTransition.md index e94d1b60789..d3f4a3b6533 100644 --- a/src/content/reference/react/ViewTransition.md +++ b/src/content/reference/react/ViewTransition.md @@ -259,10 +259,10 @@ In the future, CSS libraries may add built-in animations using View Transition C Enter/Exit Transitions trigger when a `` is added or removed by a component in a transition: -```js +```js {3} function Child() { return ( - +
Hi
); @@ -299,7 +299,6 @@ export function Video({video}) {
-
{video.title}
{video.description}
@@ -317,7 +316,7 @@ import videos from './data'; function Item() { return ( - + ); @@ -448,18 +447,148 @@ button:hover { -`` only activates if it is placed before any DOM node. If `Child` instead looked like this, no animation would trigger: +#### Only top-level ViewTransitions animate on exit/enter {/*only-top-level-viewtransition-animates-on-exit-enter*/} + +`` only activates exit/enter if it is placed _before_ any DOM nodes. + +If there's a `
` above ``, no exit/enter animations trigger: ```js [3, 5] -function Component() { - return Hi; +function Item() { + return ( +
{/* 🚩
above breaks exit/enter */} + + +
+ ); } ``` +This constraint prevents subtle bugs where too much or too little animates. + --- +### Animating enter/exit with Activity {/*animating-enter-exit-with-activity*/} + +If you want to animate a component in and out while preserving its state, or pre-rendering content for an animation, you can use [``](/reference/react/Activity). When a `` inside an `` becomes visible, the `enter` animation activates. When it becomes hidden, the `exit` animation activates: + +```js + + + + + + +``` + +In this example, `Counter` has a counter with internal state. Try incrementing the counter, hiding it, then showing it again. The counter's value is preserved while the sidebar animates in and out: + + + +```js +import { Activity, ViewTransition, useState, startTransition } from 'react'; + +export default function App() { + const [show, setShow] = useState(true); + return ( +
+ + + + + + +
+ ); +} +function Toggle({show, setShow}) { + return ( + + ) +} +function Counter() { + const [count, setCount] = useState(0); + return ( +
+

Counter

+

Count: {count}

+ +
+ ); +} + +``` + +```css +.layout { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 10px; + min-height: 200px; +} +.counter { + padding: 15px; + background: #f0f4f8; + border-radius: 8px; + width: 200px; +} +.counter h2 { + margin: 0 0 10px 0; + font-size: 16px; +} +.counter p { + margin: 0 0 10px 0; +} +.toggle { + padding: 8px 16px; + border: 1px solid #ccc; + border-radius: 6px; + background: #f0f8ff; + cursor: pointer; + font-size: 14px; +} +.toggle:hover { + background: #e0e8ff; +} +.counter button { + padding: 4px 12px; + border: 1px solid #ccc; + border-radius: 4px; + background: white; + cursor: pointer; +} +``` + +```json package.json hidden +{ + "dependencies": { + "react": "canary", + "react-dom": "canary", + "react-scripts": "latest" + } +} +``` + +
+ +Without ``, the counter would reset to `0` every time the sidebar reappears. + +--- + ### Animating a shared element {/*animating-a-shared-element*/} Normally, we don't recommend assigning a name to a `` and instead let React assign it an automatic name. The reason you might want to assign a name is to animate between completely different components when one tree unmounts and another tree mounts at the same time, to preserve continuity.