1. Introduction
React 19 introduced several new capabilities aimed at improving performance, interactivity, and developer experience. One of the most impactful additions is the new <Activity /> component, designed to let developers toggle UI sections on and off without unmounting them. This means UI can be hidden or backgrounded while still keeping its internal state, scroll position, and event listeners intact.
This pattern is especially useful for multi-panel interfaces, dashboards, wizards, and any scenario where users jump between views and expect them to stay the way they left them.
This article explores the problem the <Activity /> component solves, how it works, and provides a detailed real-life implementation example.
2. Problem
In previous versions of React, developers commonly used conditional rendering patterns such as:
{isOpen && <Sidebar />}or:
return showPanel ? <Panel /> : null;While simple, the downside is significant: the component is unmounted whenever its condition switches to false.
This leads to several persistent problems:
- Losing component state such as form fields and temporary data
- Losing scroll position in lists or long panels
- Re-executing expensive initialization logic when reopening a view
- Causing flickers or resets when switching panels
- Reduced performance when deeply nested subtrees remount
React 19’s <Activity /> component solves these issues natively.
3. Solution
The <Activity /> component allows developers to hide UI without unmounting it. Internally, React keeps the component tree in memory and pauses its rendering work while inactive.
- active={true}: The component is visible and interactive
- active={false}: The component is hidden, but state and DOM remain preserved
This makes <Activity /> ideal for dashboards, messaging apps, tab systems, multi-panel forms, and other stateful UI flows.
4. Implementation
Below is a real-life example showing how <Activity /> improves the user experience in a pizza ordering dashboard. Users switch between two panels: a complex “Build Pizza” form and a “Cart Summary.” Without <Activity />, the form resets whenever hidden. With it, all state is preserved.
Example Folder Structure
src/
components/
BuildPizzaPanel.tsx
CartSummaryPanel.tsx
App.tsxBuildPizzaPanel.tsx
import { useState } from "react";
export default function BuildPizzaPanel() {
const [size, setSize] = useState("medium");
const [toppings, setToppings] = useState<string[]>([]);
const [specialRequest, setSpecialRequest] = useState("");
function toggleTopping(topping: string) {
setToppings(prev =>
prev.includes(topping)
? prev.filter(t => t !== topping)
: [...prev, topping]
);
}
return (
<div style={{ padding: "20px" }}>
<h2>Build Your Pizza</h2>
<label>
Pizza Size:
<select value={size} onChange={e => setSize(e.target.value)}>
<option value="small">Small</option>
<option value="medium">Medium</option>
<option value="large">Large</option>
</select>
</label>
<h3>Select Toppings</h3>
{["pepperoni", "mushrooms", "onions", "sausage"].map(t => (
<div key={t}>
<label>
<input
type="checkbox"
checked={toppings.includes(t)}
onChange={() => toggleTopping(t)}
/>
{t}
</label>
</div>
))}
<h3>Special Request</h3>
<textarea
value={specialRequest}
onChange={e => setSpecialRequest(e.target.value)}
placeholder="Extra crispy crust..."
/>
<p>Selections are preserved even when panel is hidden.</p>
</div>
);
}CartSummaryPanel.tsx
export default function CartSummaryPanel() {
return (
<div style={{ padding: "20px" }}>
<h2>Your Cart</h2>
<p>This is where the order summary would appear.</p>
</div>
);
}App.tsx (Using <Activity />)
import { useState } from "react";
import { Activity } from "react";
import BuildPizzaPanel from "./components/BuildPizzaPanel";
import CartSummaryPanel from "./components/CartSummaryPanel";
export default function App() {
const [activePanel, setActivePanel] = useState<"build" | "cart">("build");
return (
<div style={{ display: "flex", gap: "20px" }}>
<div>
<button onClick={() => setActivePanel("build")}>
Build Pizza
</button>
<button onClick={() => setActivePanel("cart")}>
Cart Summary
</button>
</div>
<div style={{ flex: 1 }}>
<Activity active={activePanel === "build"}>
<BuildPizzaPanel />
</Activity>
<Activity active={activePanel === "cart"}>
<CartSummaryPanel />
</Activity>
</div>
</div>
);
}5. Conclusion
The new <Activity /> component in React 19 solves a long-standing issue caused by conditional rendering: losing UI state whenever components are hidden. It provides developers with a clean, native way to preserve state, DOM, and scroll position while improving performance and usability.
Whether you’re building dashboards, ecommerce tools, settings screens, or multi-step forms, <Activity /> offers an immediate UX upgrade with minimal changes to your codebase.