Repository: facebook/react
Pull request: Add DOM fixture page for Fragment Ref

This adds a page to the DOM fixture to test Fragment Refs. The first test case is for `addEventListener`/`removeEventListener`.

Setting `enableFragmentRefs` to `__EXPERIMENTAL__` and building is required to run the fixture.

<img width="872" alt="Screenshot 2025-03-05 at 12 58 57 PM" src="https://github.com/user-attachments/assets/fee498b7-fd96-4178-9e82-c46d4cb55c9b" />


Changed files:
filename: fixtures/dom/src/components/Header.js
patch: @@ -89,6 +89,7 @@ class Header extends React.Component {
                 <option value="/selection-events">Selection Events</option>
                 <option value="/suspense">Suspense</option>
                 <option value="/form-state">Form State</option>
+                <option value="/fragment-refs">Fragment Refs</option>
               </select>
             </label>
             <label htmlFor="global_version">

filename: fixtures/dom/src/components/fixtures/fragment-refs/index.js
patch: @@ -0,0 +1,104 @@
+import Fixture from '../../Fixture';
+import FixtureSet from '../../FixtureSet';
+import TestCase from '../../TestCase';
+
+const React = window.React;
+const {Fragment, useEffect, useRef, useState} = React;
+
+function WrapperComponent(props) {
+  return props.children;
+}
+
+function handler(e) {
+  const text = e.currentTarget.innerText;
+  alert('You clicked: ' + text);
+}
+
+export default function FragmentRefsPage() {
+  const fragmentRef = useRef(null);
+  const [extraChildCount, setExtraChildCount] = useState(0);
+
+  React.useEffect(() => {
+    fragmentRef.current.addEventListener('click', handler);
+
+    const lastFragmentRefValue = fragmentRef.current;
+    return () => {
+      lastFragmentRefValue.removeEventListener('click', handler);
+    };
+  });
+
+  return (
+    <FixtureSet title="Fragment Refs">
+      <TestCase title="Event registration">
+        <TestCase.Steps>
+          <li>Click one of the children, observe the alert</li>
+          <li>Add a new child, click it, observe the alert</li>
+          <li>Remove the event listeners, click a child, observe no alert</li>
+          <li>
+            Add the event listeners back, click a child, observe the alert
+          </li>
+        </TestCase.Steps>
+
+        <TestCase.ExpectedResult>
+          <p>
+            Fragment refs can manage event listeners on the first level of host
+            children. This page loads with an effect that sets up click event
+            hanndlers on each child card. Clicking on a card will show an alert
+            with the card's text.
+          </p>
+          <p>
+            New child nodes will also have event listeners applied. Removed
+            nodes will have their listeners cleaned up.
+          </p>
+        </TestCase.ExpectedResult>
+
+        <Fixture>
+          <div className="control-box" id="control-box">
+            <div>Target count: {extraChildCount + 3}</div>
+            <button
+              onClick={() => {
+                setExtraChildCount(prev => prev + 1);
+              }}>
+              Add Child
+            </button>
+            <button
+              onClick={() => {
+                fragmentRef.current.addEventListener('click', handler);
+              }}>
+              Add click event listeners
+            </button>
+            <button
+              onClick={() => {
+                fragmentRef.current.removeEventListener('click', handler);
+              }}>
+              Remove click event listeners
+            </button>
+            <div class="card-container">
+              <Fragment ref={fragmentRef}>
+                <div className="card" id="child-a">
+                  Child A
+                </div>
+                <div className="card" id="child-b">
+                  Child B
+                </div>
+                <WrapperComponent>
+                  <div className="card" id="child-c">
+                    Child C
+                  </div>
+                  {Array.from({length: extraChildCount}).map((_, index) => (
+                    <div
+                      className="card"
+                      id={'extra-child-' + index}
+                      key={index}>
+                      Extra Child {index}
+                    </div>
+                  ))}
+                </WrapperComponent>
+              </Fragment>
+            </div>
+          </div>
+        </Fixture>
+      </TestCase>
+    </FixtureSet>
+  );
+}

filename: fixtures/dom/src/style.css
patch: @@ -309,3 +309,16 @@ th {
 tbody tr:nth-child(even) {
   background: #f0f0f0;
 }
+
+.card-container {
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.card {
+  background: white;
+  border-radius: 2px;
+  border: 1px solid rgba(0, 0, 0, 0.24);
+  margin: 10px;
+  padding: 10px;
+}