PixelPortal

SSR-safe portal primitive: renders children inline on the server and while hydrating, then portals them into document.body or a container, keeping the focus set inside them.

  • SSR-safe: renders inline on the server and during hydration to avoid hydration mismatches
  • Focus set inside the content stays put as the content reaches its target
  • Targets document.body by default; the container prop picks another element
  • Can be disabled to keep its content inline (useful for testing or conditional portaling)
  • The content keeps its place in the component tree, so providers still reach it (in React, its events also bubble through that tree)
Status
stable
Category
overlay-foundation
Since
v1.8.0

API

import { PixelPortal } from '@pxlkit/ui-kit';
PropTypeDefaultDescription
children (required)React.ReactNode—Content to render in the target.
containerHTMLElement | null—Target element; document.body when left out.
disabledboolean—Keep the content in place.

ref points to <div>.

Accessibility

WCAG target: 2.1 AA

  • SSR-safe portal
  • context preserved through the component tree

Portal content keeps its place in the component tree, so providers reach it as if it were rendered in place; in React, its events also bubble through that tree. Keyboard focus follows the document order, where the content sits in its target.

Usage

import { PixelPortal } from '@pxlkit/ui-kit';

export function Default() {
  return (
    <PixelPortal>
      <div>Portaled content (renders into document.body after mount)</div>
    </PixelPortal>
  )
}

Examples

Default

import { PixelPortal } from '@pxlkit/ui-kit';

export function Default() {
  return (
    <PixelPortal>
      <div>Portaled content (renders into document.body after mount)</div>
    </PixelPortal>
  )
}

Disabled (inline)

import { PixelPortal } from '@pxlkit/ui-kit';

export function Disabled() {
  return (
    <PixelPortal disabled>
      <div>Rendered inline — portal disabled</div>
    </PixelPortal>
  )
}