How to Use the React 19 Activity Component: Full Guide with Real Examples

3 min read

How to Use the React 19  Activity Component: Full Guide with Real Examples

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.tsx

BuildPizzaPanel.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.

🤞 Never miss a story from us, get weekly updates to your inbox!

Leave a Reply

Your email address will not be published. Required fields are marked *