[DOM] Blur focused descendants in Fragment refs (#37125)
## Summary `FragmentInstance.blur()` only matched the active element against the first level of host children. If the focused element was nested inside one of those children, `focus()` could reach it but `blur()` would leave it focused. This treats an active element contained by a Fragment host child as part of the Fragment and blurs the active element itself. It also adds regression coverage for a nested input. Fixes #37124. ## How did you test this change? - `yarn test ReactDOMFragmentRefs-test --runInBand` (65 tests passed) - `yarn test --prod ReactDOMFragmentRefs-test --runInBand` (65 tests passed) - `yarn prettier` - `yarn linc` - `yarn flow dom-node`
Minh Vu committed
Jul 29, 2026 at 18:21 UTC
1724e9ce0aa1db99bcbe2633304b6a0fee2e4e1e
2 files changed
+32
-2
packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
+2
-2
@@ -3262,9 +3262,9 @@ function blurActiveElementWithinFragment(
3262
return false;
3263
}
3264
const instance = getInstanceFromHostFiber<Instance>(child);
3265
- if (instance === activeElement) {
3265
+ if (instance === activeElement || instance.contains(activeElement)) {
3266
// $FlowFixMe[prop-missing]
3267
- instance.blur();
3267
+ activeElement.blur();
3268
return true;
3269
}
3270
return false;
packages/react-dom/src/__tests__/ReactDOMFragmentRefs-test.js
+30
@@ -454,6 +454,36 @@ describe('FragmentRefs', () => {
454
expect(document.activeElement).toEqual(document.body);
455
});
456
457
+ // @gate enableFragmentRefs
458
+ it('removes focus from a nested element inside of the Fragment', async () => {
459
+ const fragmentRef = React.createRef();
460
+ const root = ReactDOMClient.createRoot(container);
461
+
462
+ function Test() {
463
+ return (
464
+ <Fragment ref={fragmentRef}>
465
+ <div>
466
+ <input id="nested-input" />
467
+ </div>
468
+ </Fragment>
469
+ );
470
+ }
471
+
472
+ await act(() => {
473
+ root.render(<Test />);
474
+ });
475
+
476
+ await act(() => {
477
+ fragmentRef.current.focus();
478
+ });
479
+ expect(document.activeElement.id).toEqual('nested-input');
480
+
481
+ await act(() => {
482
+ fragmentRef.current.blur();
483
+ });
484
+ expect(document.activeElement).toEqual(document.body);
485
+ });
486
+
487
// @gate enableFragmentRefs
488
it('does not remove focus from elements outside of the Fragment', async () => {
489
const fragmentRefA = React.createRef();