With the release of React 19.2 (Oct 2025), React adds a powerful new primitive: the <Activity> component. This gives developers fine-grained control over rendering subtrees: you can hide them visually, suspend their effects, and defer their updates—yet preserve their React state and DOM structure for when they come back.
Traditionally, UI toggles have forced a trade-off:
- Conditionally rendering: {isVisible && <component/>} — destroys component tree when hidden > you lose all state.
- CSS-based hiding: <div style={{display: 'none'}}><component/></div— preserves state, but all effects and updates keep running > wasted resources, unexpected side-effects.
<Activity> sits in the sweet spot: state kept, effects suspended, updates deferred, giving you smooth, performant UI transitions.
What <Activity> does
Modes: visible vs hidden
<Activity mode={isVisible ? "visible" : "hidden"}>
<MyComponent />
</Activity> - visible: children are visible, effects are mounted, and updates are processed normally.
- hidden: children are visually hidden via display: none, their effects are cleaned up (subscriptions, timers canceled), and any updates are deferred until React is idle.
When the component becomes visible again, React restores the previous state (both React and DOM), and remounts effects as needed.
When to use <Activity> : use-cases
Here are some practical situations where <Activity> shines:
- Tabbed interfaces / multi-page apps: Keep hidden pages mounted so that when users switch tabs, their form inputs, scroll positions, or UI state remain intact—without wasting CPU on background tasks.
- Modals, drawers, sidebars: Hide them visually but preserve their internal state (e.g., draft content, scroll position).
- User navigations/previews: Pre-render components that the user is likely to visit next (e.g. next page, next tab), so when they navigate, it feels instant.
- Media previews/video players: Pause effects (like video playback) when hidden, but remember the playback position so that when user returns, it's unchanged.
- Complex forms or wizards: Users can step away and return without losing data or prematurely triggering side effects.
Often using <Activity> yields better UX and performance than either naive conditional rendering or always-mounted CSS hiding.
Example—Tabs preserving state
Here’s a minimal example of a tabbed UI where each tab preserves its state (e.g., input data) even when hidden:
import { Activity, useState } from "react";
function App() {
const [activeTab, setActiveTab] = useState('home');
return (
<>
<nav>
<button
onClick={() => setActiveTab("home")}
className="p-2 hover:underline"
>
Home
</button>
<button
onClick={() => setActiveTab("profile")}
className="p-2 hover:underline"
>
Profile
</button>
</nav>
<Activity mode={activeTab === "home" ? "visible" : "hidden"}>
<HomeTab />
</Activity>
<Activity mode={activeTab === "profile" ? "visible" : "hidden"}>
<ProfileTab />
</Activity>
</>
);
}
function HomeTab() {
const [text, setText] = useState("");
return (
<input
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="Home tab input"
className="m-2 border"
/>
);
}
function ProfileTab() {
const [bio, setBio] = useState("");
return (
<textarea
value={bio}
onChange={(e) => setBio(e.target.value)}
placeholder="Profile tab bio"
className="m-2 border"
/>
);
}Caveats & what to watch out for
- If you wrap a component that only returns text (not a DOM element), hidden mode may effectively remove it completely (since there’s no wrapper to apply display: none).
- Hidden components still re-render on prop updates, albeit at lower priority—so you need to be mindful if props change frequently.
- Using doesn’t completely eliminate memory usage—the DOM nodes + React state remain. So, avoid wrapping heavy components that you seldom re-show.
- Some UI patterns (like animations or lifecycle side-effects tied to visibility) may require additional handling to work smoothly when toggling visibility.
Conclusion
The <Activity> component in React 19.2 is a game-changer for building complex, stateful UI with smooth performance. It gives you a third way—not just “render or don’t render”, nor “hide with CSS and keep everything running”—but a hybrid that preserves UI and state without unnecessary work.
For tabbed apps, modals, forms, previews, or any UI that you hide and show repeatedly—replacing conditional rendering with <Activity> can yield smoother interactions, a better memory footprint, and simpler code.
To read more about How to Implement React Server Components, refer to our blog, How to Implement React Server Components.