Skip to content

Prep for React 19#4416

Draft
lbwexler wants to merge 8 commits into
developfrom
react-19
Draft

Prep for React 19#4416
lbwexler wants to merge 8 commits into
developfrom
react-19

Conversation

@lbwexler

@lbwexler lbwexler commented Jun 7, 2026

Copy link
Copy Markdown
Member

React-18-safe preparation for an eventual React 19 upgrade. Every change here is forward-compatible — it behaves identically on React 18 and just removes an API/component that React 19 drops or breaks. No runtime bump, so this can merge to develop independently of any React 19 timeline.

Changes

  • findDOMNode removalHoistInputModel.domEl now resolves its element directly from domRef rather than falling back to the React-19-removed findDOMNode. A trace of all 25 desktop + mobile HoistInput implementations confirms each already roots domRef on a DOM element (host element, Blueprint forwardRef control, or react-onsenui's forwardRef-to-host chain), so the fallback was defensive legacy.
  • Blueprint PopoverPopoverNext — the kit/blueprint Popover wrapper now renders Blueprint's Floating UI-based PopoverNext (React 19 compatible) instead of the legacy findDOMNode-based Popover. It converts our existing PopoverProps API via Blueprint's popoverPropsToNextProps helper (maps position/modifiers/minimal/boundary and preserves the legacy shouldReturnFocusOnClose default), so the public popover factory API is unchanged and no call sites need edits. (Overlay was already migrated to Overlay2.)
  • Mobile Popover: react-popper@floating-ui/react — swapped usePopper for useFloating, reusing the same Floating UI library Blueprint already pulls in (deduped to a single copy rather than adding a new dependency). Removed react-popper as a direct dependency and dropped the obsolete Popper.js-specific popperOptions prop.

Deferred to the actual React 19 migration (not in this PR)

  • forwardRef → ref-as-prop — deprecated but still works in React 19, so it's not a blocker; and ref-as-prop is React-19-only, so it can't be done while on 18.
  • @types/react@19 / peer-range bump and the Blueprint / react-onsenui peer-dep resolutions overrides.

Testing

Verified in toolbox via startWithHoist (React 18.2.0 / Blueprint 6.15.0): the desktop app-menu, GroupingChooser, and FilterChooser popovers plus the Select input / filter lifecycle all work with zero console errors or warnings. The mobile app builds and loads cleanly on the Floating UI swap (no module/resolution errors), but the mobile Popover's open/positioning was not exercised through the toolbox UI (its only consumer is the app-menu, which isn't surfaced in the current mobile screens) — worth a manual mobile spot-check.

See docs/planning/react-19-upgrade.md for the full plan. Refs #4205.

lbwexler added 8 commits June 5, 2026 17:25
findDOMNode is removed in React 19. HoistInputModel.domEl used it as a
fallback for the case where domRef.current resolved to a class-component
instance rather than a DOM element. A trace of all 25 desktop + mobile
HoistInput implementations confirms every one roots domRef on a DOM
element (host element, Blueprint forwardRef control, or react-onsenui's
forwardRef-to-host chain), so the fallback was defensive legacy and is
never exercised. domEl now resolves the element directly from the ref.

Behavior-preserving on React 18; forward-compatible with React 19.
…19 prep)

The legacy Blueprint Popover relies on the removed findDOMNode and breaks
under React 19. PopoverNext (Floating UI based) is its React-19-compatible
replacement, shipped in the same Blueprint build and running on React 18 -
the same approach already used for Overlay2.

The kit Popover wrapper now renders PopoverNext, converting our existing
legacy PopoverProps API via Blueprint's popoverPropsToNextProps helper
(maps position/modifiers/minimal/boundary and preserves the legacy
shouldReturnFocusOnClose=false default). The public popover factory API is
unchanged, so none of the ~20 call sites need edits. Verified no call site
uses an unmappable legacy-only prop (modifiersCustom,
portalStopPropagationEvents, wrapperTagName, targetClassName).
…ct 19 prep)

react-popper (Popper.js) is deprecated, its repo archived, and its peer dep
caps at React 18 - a genuine code incompatibility with React 19. The mobile
Popover was its only consumer.

Swapped usePopper for @floating-ui/react's useFloating, reusing the same
Floating UI library Blueprint's PopoverNext already pulls in (deduped to a
single 0.27.x copy) rather than adding a separate dependency. Placement names
are shared between the two libraries so menuPositionToPlacement is unchanged;
the preventOverflow modifier maps to shift({padding: 10}), 'auto' position
maps to autoPlacement(), and scroll/resize tracking uses autoUpdate.

Removed react-popper as a direct dependency (it remains transitively via
Blueprint's legacy Popover until Blueprint v7) and removed the now-obsolete
Popper.js-specific popperOptions prop from the mobile Popover.
@lbwexler lbwexler mentioned this pull request Jun 7, 2026
@lbwexler lbwexler changed the title Final Prep for React 19 Prep for React 19 Jun 7, 2026
@lbwexler

lbwexler commented Jun 7, 2026

Copy link
Copy Markdown
Member Author

Tested the migrated mobile Popover (Blueprint PopoverNext + Floating UI) in Toolbox mobile on this branch — popovers open, position, and dismiss correctly. Working fine here on react-19 (React 18).

Note: mobile popovers did not appear to work on the stacked react-19-upgrade branch (actual React 19 bump) — investigating that separately.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant