eoria
Component

Portal

Render children at the root, above navigation. The primitive behind every overlay.

Portal rendered on iOS, light mode
Portal rendered on iOS, dark mode
iPhone, zinc preset. Captured from the example app.
Terminal window
npx @eoria/cli add portal

Usage

import { Portal, PortalHost } from '@/components/ui/portal'
// once, last in the root layout
<PortalHost />
// anywhere
<Portal modal>{overlay}</Portal>

Notes

  • A module store plus useSyncExternalStore, no native Modal. Same behaviour on every platform, and it never fights the navigator.
  • modal marks the host accessibilityViewIsModal while mounted, which hides the rest of the app from VoiceOver.
  • React context does not cross the portal. Components that need it re-provide it inside their portal content. Dialog, Popover, DropdownMenu and Select all do.
  • The host measures its own window offset so anchored content can convert measureInWindow coordinates. It always mounts, with pointerEvents="box-none", so it never blocks touches.

Source

registry/ui/portal.tsx