Skip to content

DataTable: TableBulkActions re-creates a MutationObserver on document.body every render #8715

Open

Description

@mattcosta7

Part of #8676 (P0).

Problem

DataTable/TableBulkActions.tsx:58-63 runs a useLayoutEffect with no dependency array. Each run calls observeFocusedAction() (:48), which creates a new MutationObserver on element.ownerDocument.body with {childList: true, subtree: true}. So every render of the bulk actions bar disconnects and rebuilds a document-wide observer.

onFocusCapture already calls observeFocusedAction() when focus moves into the bar, so the per-render effect is redundant for focus tracking.

Verified in code but not measured.

Proposed fix

Do one of the following:

  • Drop the per-render call and rely on onFocusCapture, keeping only an unmount cleanup that disconnects the observer.
  • Give the effect a dependency such as selectedCount.

recoverFocus() must still run when an action unmounts while focused.

Acceptance criteria

  • Re-rendering TableBulkActions with unchanged props doesn't create a new MutationObserver.
  • Focus recovery still works when the focused bulk action is removed. Add or keep a test for this.
  • Unmounting disconnects the observer.

Activity

  1. Muguett-DBY commented on Nov 13, 2026

    @Muguett-DBY

    One edge case to keep when simplifying the effect: the observer callback captures onFocusReturn from the render where the action was focused.

    I focused an action, re-rendered with a new onFocusReturn while selectedCount stayed at 1, then removed the action through its own state update. Current main calls the new callback; both an unmount-only effect and an effect depending only on selectedCount call the old one. A regression test for that sequence would help; keeping the latest callback in a ref is one possible approach.

    I checked this at 324b0aa with React 19.2.7 and jsdom 29.1.1. This was an isolated component test with styling and supporting imports mocked, not the full suite or a real browser. Tested with Codex assistance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions