Skip to content

How to properly deal with portal containers and the fullscreen API? #10506

Description

@snowystinger

Discussed in #9206

Originally posted by janvorwerk November 19, 2025
Hello gents,

My app is using the DOM fullscreen API for several cases.

Let's consider two of them:

  1. Part of the screen needs a lot of screen space… and still has many interactions that will open portaled content (popover…)
  2. A dialog (Modal for instance) is showing a Youtube iframe, in which the user wants to trigger full screen mode to better view the video

By default, case 1 does not work because as soon as the component goes fullscreen, the document.body seems no longer visible so that any portaled component isn't either.

What I thought was a very smart move was to use the PortalProvider… despite the fact that it was flagged "UNSAFE".

export function SkPortalProvider(props: { children: ReactNode }) {
  return <UNSAFE_PortalProvider getContainer={getDomRoot}>{props.children}</UNSAFE_PortalProvider>;
}

function getDomRoot(): HTMLElement | null {
  return document?.fullscreenElement instanceof HTMLElement ? document.fullscreenElement : document.body;
}

Clever, ugh? Actually not so much because then, case 2 won't work any longer : as soon as the video goes fullscreen, the portal is changed, so that the dialog containing the video node vanishes…

Then I tried to be more clever than ever 😁…

function getDomRoot(): HTMLElement | null {
    // If there are existing modals/dialogs in document.body, keep using document.body
    // to avoid moving them when fullscreen is triggered. This prevents modals from
    // disappearing when fullscreen is activated.
    const hasExistingModals = document.body?.querySelector('[role="dialog"], [role="alertdialog"]') != null;
    
    if (hasExistingModals) {
      return document.body;
    }
    
    // Otherwise, use fullscreen element if available (for popovers within fullscreen),
    // or document.body as fallback
    return document?.fullscreenElement instanceof HTMLElement ? document.fullscreenElement : document.body;
}

… but then case 1 no longer works properly…

Hence my questions: did you guys consider using/supporting fullscreen? How did you do?

Many thanks in advance 🙏

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions