Skip to content

autoResize misses absolutely-positioned portal growth (popover opens → no size-changed) #686

@plmercereau

Description

@plmercereau

Problem

With autoResize: true (the useApp() default), opening any portal-based popover — a date-picker calendar, a Select dropdown, a tooltip — never emits ui/notifications/size-changed, so the host iframe stays at the pre-popover height and the popover is clipped.

Two independent gaps in setupSizeChangedNotifications (v1.7.4):

  1. Trigger gap: the ResizeObserver watches only document.documentElement and document.body border-boxes. Component libraries (Mantine, Radix, MUI, Floating UI…) render popovers into an absolutely-positioned portal appended to <body> — typically inside a zero-height positioned wrapper. Neither observed border-box changes, so no measurement is ever scheduled.
  2. Measurement gap: even when a measure does run, it reports documentElement.getBoundingClientRect().height under a transient height: max-content — which excludes out-of-flow content. An absolutely-positioned dropdown extending past the in-flow content does not contribute, so the reported height is unchanged anyway. (fix(app): autoResize collapses height:100% layouts; expose autoResize in useApp #619's proposed body.scrollHeight measure would fix this half, but not gap 1.)

Repro

Any React app embedded via the SDK:

const { app } = useApp({ appInfo, capabilities: {} }); // autoResize default
// render a Mantine <DatePickerInput /> near the bottom of the content

Click the input → calendar opens in a portal, extends ~300px past the content → no size-changed notification → host iframe clips the calendar. Verified against a host that resizes the iframe to every reported height (our wire-contract harness drives AppBridge directly).

Workaround we ship

A MutationObserver on body funnelled through the public API:

useEffect(() => {
  if (!app) return;
  const report = () =>
    app.sendSizeChanged({
      width: Math.ceil(window.innerWidth),
      height: Math.max(
        document.body.scrollHeight,
        document.documentElement.scrollHeight,
      ),
    });
  const mo = new MutationObserver(report);
  mo.observe(document.body, { childList: true, subtree: true, attributes: true });
  return () => mo.disconnect();
}, [app]);

scrollHeight includes the out-of-flow portal; the MutationObserver supplies the missing trigger.

Suggested fix

In setupSizeChangedNotifications, add a (debounced) MutationObserver on body alongside the existing ResizeObserver, and measure with Math.max(body.scrollHeight, documentElement.scrollHeight) (compatible with the direction #619 proposes) so out-of-flow portals are both detected and measured.

Related: #502 (height-management umbrella), #619 (measurement strategy), #567 (auto-resize side effects).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions