Skip to main content

Installation

npm install @kuzenbo/core

Usage

import { Portal } from "@kuzenbo/core";

function Example() {
  return (
    <Portal>
      <div className="fixed top-4 right-4 bg-background border rounded-lg p-4 shadow-lg">
        This is rendered in a portal
      </div>
    </Portal>
  );
}

Props

children
ReactNode
required
The content to render in the portal.
target
HTMLElement | string | RefObject<HTMLElement>
The target container. Can be:
  • An HTMLElement
  • A CSS selector string
  • A React ref If not provided, creates a new div appended to document.body.
reuseTargetNode
boolean
default:"true"
If true, all portals share the same DOM node.
className
string
CSS classes to apply to the portal container.
style
CSSProperties
Inline styles to apply to the portal container.
id
string
ID attribute for the portal container.

Examples

Basic Portal

<Portal>
  <div>Rendered at document.body</div>
</Portal>

Specific Target Element

const targetRef = useRef<HTMLDivElement>(null);

<>
  <div ref={targetRef} id="portal-target" />
  <Portal target={targetRef}>
    <div>Rendered in the target element</div>
  </Portal>
</>

Target by CSS Selector

<Portal target="#modal-root">
  <div>Rendered in #modal-root</div>
</Portal>

Separate Portal Nodes

<Portal reuseTargetNode={false}>
  <div>This gets its own portal container</div>
</Portal>

Styled Portal Container

<Portal
  className="portal-container"
  style={{ zIndex: 9999 }}
>
  <div>Content with styled container</div>
</Portal>
function Modal({ open, children }: { open: boolean; children: ReactNode }) {
  if (!open) return null;

  return (
    <Portal>
      <div className="fixed inset-0 z-50 bg-background/80 backdrop-blur-sm">
        <div className="fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
          <div className="bg-background border rounded-lg shadow-lg p-6">
            {children}
          </div>
        </div>
      </div>
    </Portal>
  );
}

Toast Notifications

function ToastContainer() {
  return (
    <Portal>
      <div className="fixed bottom-4 right-4 z-50 flex flex-col gap-2">
        {toasts.map((toast) => (
          <div key={toast.id} className="bg-background border rounded-lg p-4 shadow-lg">
            {toast.message}
          </div>
        ))}
      </div>
    </Portal>
  );
}

Floating UI Elements

<Portal>
  <div
    className="fixed bg-popover border rounded-md shadow-md"
    style={{
      top: position.y,
      left: position.x,
    }}
  >
    Floating content
  </div>
</Portal>

Conditional Portal

function ConditionalPortal({ usePortal, children }: { usePortal: boolean; children: ReactNode }) {
  if (usePortal) {
    return <Portal>{children}</Portal>;
  }
  return <>{children}</>;
}

Build docs developers (and LLMs) love