From 6e798e46892c435ea0df8f55d2ac809f63ba44f0 Mon Sep 17 00:00:00 2001 From: Joseph Chamochumbi Date: Fri, 24 Oct 2025 13:38:09 +0200 Subject: [PATCH 1/5] docs: Routes are wrapped w/ Activity in Cache Components --- .../04-linking-and-navigating.mdx | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/docs/01-app/01-getting-started/04-linking-and-navigating.mdx b/docs/01-app/01-getting-started/04-linking-and-navigating.mdx index 2efa978bd3f89..8ccedfc9403f1 100644 --- a/docs/01-app/01-getting-started/04-linking-and-navigating.mdx +++ b/docs/01-app/01-getting-started/04-linking-and-navigating.mdx @@ -331,6 +331,45 @@ React mitigates this with Selective Hydration and you can further improve this b - Using the [`@next/bundle-analyzer`](/docs/app/guides/package-bundling#analyzing-javascript-bundles) plugin to identify and reduce bundle size by removing large dependencies. - Moving logic from the client to the server where possible. See the [Server and Client Components](/docs/app/getting-started/server-and-client-components) docs for guidance. +## Navigation with Cache Components + +When the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) flag is enabled, Next.js uses React's [``](https://react.dev/reference/react/Activity) component to preserve component state during client-side navigation. + +Instead of unmounting the previous route when you navigate away, Next.js hides it with `display: none`. This means: + +- Component state is preserved when navigating between routes +- When you navigate back, the previous route reappears with its state intact +- Effects are cleaned up when a route is hidden, and recreated when it becomes visible again + +This behavior improves the navigation experience by maintaining UI state (form inputs, or expanded sections) when users navigate back and forth between routes. + +> **Good to know**: Next.js uses heuristics to keep a few recently visited routes hidden with Activity to preserve their state, while older routes are removed from the DOM to prevent excessive growth. + +
+**Portals under Activity require manual cleanup** + +As a consequence of routes being hidden rather than unmounted, portals created via [`createPortal`](https://react.dev/reference/react-dom/createPortal) need special handling. Since portals render outside their parent component's DOM tree, they bypass the CSS cascade and remain visible even when the parent route is hidden. + +React can't automatically hide portals because it doesn't control the portal container—your effect does. To fix this, add a cleanup function to your effect: + +```tsx highlight={6-10} +useLayoutEffect(() => { + const el = document.getElementById('portal-root') + setContainer(el) + + // Hide the portal container when this component is hidden by Activity + return () => { + if (el) el.style.display = 'none' + } +}, []) +``` + +The cleanup function runs when the component's Effects are cleaned up by the Activity boundary. + +Whether portal elements should automatically become visible again when the Activity is shown depends on your specific UI needs. + +
+ ## Examples ### Native History API From 4fc591a79ed8f7de5181cd7e48b0b8d0d9edfa29 Mon Sep 17 00:00:00 2001 From: Joseph Chamochumbi Date: Fri, 24 Oct 2025 14:32:51 +0200 Subject: [PATCH 2/5] docs: Activity routes feedback --- .../01-getting-started/04-linking-and-navigating.mdx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/01-app/01-getting-started/04-linking-and-navigating.mdx b/docs/01-app/01-getting-started/04-linking-and-navigating.mdx index 8ccedfc9403f1..84f0f45645328 100644 --- a/docs/01-app/01-getting-started/04-linking-and-navigating.mdx +++ b/docs/01-app/01-getting-started/04-linking-and-navigating.mdx @@ -335,7 +335,7 @@ React mitigates this with Selective Hydration and you can further improve this b When the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) flag is enabled, Next.js uses React's [``](https://react.dev/reference/react/Activity) component to preserve component state during client-side navigation. -Instead of unmounting the previous route when you navigate away, Next.js hides it with `display: none`. This means: +Rather than unmounting the previous route when you navigate away, Next.js sets the Activity mode to [`"hidden"`](https://react.dev/reference/react/Activity#activity). This means: - Component state is preserved when navigating between routes - When you navigate back, the previous route reappears with its state intact @@ -348,9 +348,9 @@ This behavior improves the navigation experience by maintaining UI state (form i
**Portals under Activity require manual cleanup** -As a consequence of routes being hidden rather than unmounted, portals created via [`createPortal`](https://react.dev/reference/react-dom/createPortal) need special handling. Since portals render outside their parent component's DOM tree, they bypass the CSS cascade and remain visible even when the parent route is hidden. +As a consequence of routes being hidden rather than unmounted, portals created via [`createPortal`](https://react.dev/reference/react-dom/createPortal) need special handling. Since portals render outside their parent component's DOM tree, they remain visible even when the parent route is hidden. -React can't automatically hide portals because it doesn't control the portal container—your effect does. To fix this, add a cleanup function to your effect: +React can't automatically hide portals because it doesn't control the portal container, your effect does. To fix this, add a cleanup function to your effect: ```tsx highlight={6-10} useLayoutEffect(() => { @@ -364,10 +364,12 @@ useLayoutEffect(() => { }, []) ``` -The cleanup function runs when the component's Effects are cleaned up by the Activity boundary. +The cleanup function runs when the component's effects are cleaned up by the Activity boundary. Whether portal elements should automatically become visible again when the Activity is shown depends on your specific UI needs. +For more about handling side effects and UI with hidden components, see [React’s guide to unwanted side-effects in hidden components](https://react.dev/reference/react/Activity#my-hidden-components-have-unwanted-side-effects). +
## Examples From fb027023318543f4362f3d4871ea4bfd000c25ea Mon Sep 17 00:00:00 2001 From: Joseph Chamochumbi Date: Fri, 24 Oct 2025 14:33:58 +0200 Subject: [PATCH 3/5] docs: Activity become visible or hidden --- docs/01-app/01-getting-started/04-linking-and-navigating.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/01-app/01-getting-started/04-linking-and-navigating.mdx b/docs/01-app/01-getting-started/04-linking-and-navigating.mdx index 84f0f45645328..587ce079d702f 100644 --- a/docs/01-app/01-getting-started/04-linking-and-navigating.mdx +++ b/docs/01-app/01-getting-started/04-linking-and-navigating.mdx @@ -366,7 +366,7 @@ useLayoutEffect(() => { The cleanup function runs when the component's effects are cleaned up by the Activity boundary. -Whether portal elements should automatically become visible again when the Activity is shown depends on your specific UI needs. +Whether portal elements should automatically become visible again when the Activity is `"visible"` again depends on your specific UI needs. For more about handling side effects and UI with hidden components, see [React’s guide to unwanted side-effects in hidden components](https://react.dev/reference/react/Activity#my-hidden-components-have-unwanted-side-effects). From 92624061ec47348455e90334d68c39099a954360 Mon Sep 17 00:00:00 2001 From: Joseph Date: Tue, 28 Oct 2025 15:32:57 +0100 Subject: [PATCH 4/5] Update docs/01-app/01-getting-started/04-linking-and-navigating.mdx --- docs/01-app/01-getting-started/04-linking-and-navigating.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/01-app/01-getting-started/04-linking-and-navigating.mdx b/docs/01-app/01-getting-started/04-linking-and-navigating.mdx index 587ce079d702f..0a6701631778c 100644 --- a/docs/01-app/01-getting-started/04-linking-and-navigating.mdx +++ b/docs/01-app/01-getting-started/04-linking-and-navigating.mdx @@ -343,7 +343,7 @@ Rather than unmounting the previous route when you navigate away, Next.js sets t This behavior improves the navigation experience by maintaining UI state (form inputs, or expanded sections) when users navigate back and forth between routes. -> **Good to know**: Next.js uses heuristics to keep a few recently visited routes hidden with Activity to preserve their state, while older routes are removed from the DOM to prevent excessive growth. +> **Good to know**: Next.js uses heuristics to keep a few recently visited routes [`"hidden"`](https://react.dev/reference/react/Activity#activity), while older routes are removed from the DOM to prevent excessive growth.
**Portals under Activity require manual cleanup** From 6de5cb0518499ce94222e908b4c6cd870fece57b Mon Sep 17 00:00:00 2001 From: Joseph Chamochumbi Date: Tue, 28 Oct 2025 15:54:14 +0100 Subject: [PATCH 5/5] docs: Move bfcache w/ Activity to Cache Components docs --- .../04-linking-and-navigating.mdx | 41 ------------------- .../06-cache-components.mdx | 14 +++++++ 2 files changed, 14 insertions(+), 41 deletions(-) diff --git a/docs/01-app/01-getting-started/04-linking-and-navigating.mdx b/docs/01-app/01-getting-started/04-linking-and-navigating.mdx index 0a6701631778c..2efa978bd3f89 100644 --- a/docs/01-app/01-getting-started/04-linking-and-navigating.mdx +++ b/docs/01-app/01-getting-started/04-linking-and-navigating.mdx @@ -331,47 +331,6 @@ React mitigates this with Selective Hydration and you can further improve this b - Using the [`@next/bundle-analyzer`](/docs/app/guides/package-bundling#analyzing-javascript-bundles) plugin to identify and reduce bundle size by removing large dependencies. - Moving logic from the client to the server where possible. See the [Server and Client Components](/docs/app/getting-started/server-and-client-components) docs for guidance. -## Navigation with Cache Components - -When the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) flag is enabled, Next.js uses React's [``](https://react.dev/reference/react/Activity) component to preserve component state during client-side navigation. - -Rather than unmounting the previous route when you navigate away, Next.js sets the Activity mode to [`"hidden"`](https://react.dev/reference/react/Activity#activity). This means: - -- Component state is preserved when navigating between routes -- When you navigate back, the previous route reappears with its state intact -- Effects are cleaned up when a route is hidden, and recreated when it becomes visible again - -This behavior improves the navigation experience by maintaining UI state (form inputs, or expanded sections) when users navigate back and forth between routes. - -> **Good to know**: Next.js uses heuristics to keep a few recently visited routes [`"hidden"`](https://react.dev/reference/react/Activity#activity), while older routes are removed from the DOM to prevent excessive growth. - -
-**Portals under Activity require manual cleanup** - -As a consequence of routes being hidden rather than unmounted, portals created via [`createPortal`](https://react.dev/reference/react-dom/createPortal) need special handling. Since portals render outside their parent component's DOM tree, they remain visible even when the parent route is hidden. - -React can't automatically hide portals because it doesn't control the portal container, your effect does. To fix this, add a cleanup function to your effect: - -```tsx highlight={6-10} -useLayoutEffect(() => { - const el = document.getElementById('portal-root') - setContainer(el) - - // Hide the portal container when this component is hidden by Activity - return () => { - if (el) el.style.display = 'none' - } -}, []) -``` - -The cleanup function runs when the component's effects are cleaned up by the Activity boundary. - -Whether portal elements should automatically become visible again when the Activity is `"visible"` again depends on your specific UI needs. - -For more about handling side effects and UI with hidden components, see [React’s guide to unwanted side-effects in hidden components](https://react.dev/reference/react/Activity#my-hidden-components-have-unwanted-side-effects). - -
- ## Examples ### Native History API diff --git a/docs/01-app/01-getting-started/06-cache-components.mdx b/docs/01-app/01-getting-started/06-cache-components.mdx index cac2803ce4eac..d115604ca8e5c 100644 --- a/docs/01-app/01-getting-started/06-cache-components.mdx +++ b/docs/01-app/01-getting-started/06-cache-components.mdx @@ -333,6 +333,20 @@ const nextConfig = { module.exports = nextConfig ``` +### Navigation with Cache Components + +When the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) flag is enabled, Next.js uses React's [``](https://react.dev/reference/react/Activity) component to preserve component state during client-side navigation. + +Rather than unmounting the previous route when you navigate away, Next.js sets the Activity mode to [`"hidden"`](https://react.dev/reference/react/Activity#activity). This means: + +- Component state is preserved when navigating between routes +- When you navigate back, the previous route reappears with its state intact +- Effects are cleaned up when a route is hidden, and recreated when it becomes visible again + +This behavior improves the navigation experience by maintaining UI state (form inputs, or expanded sections) when users navigate back and forth between routes. + +> **Good to know**: Next.js uses heuristics to keep a few recently visited routes [`"hidden"`](https://react.dev/reference/react/Activity#activity), while older routes are removed from the DOM to prevent excessive growth. + ### Effect on route segment config When Cache Components is enabled, several route segment config options are no longer needed or supported. Here's what changes and how to migrate: