Documentation Index
Fetch the complete documentation index at: https://mintlify.com/zayne-labs/ui/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The Teleport component (also known as Portal) renders its children into a different part of the DOM tree while maintaining the React component hierarchy. This is useful for modals, tooltips, dropdowns, and other overlay components.
Import
import { Teleport } from "@zayne-labs/ui-react/common/teleport";
Props
The content to render in the portal.
to
string | HTMLElement | React.RefObject<HTMLElement> | ValidHtmlTags | null
required
The destination for the portal. Can be:
- A CSS selector string (e.g., “#modal-root”)
- An HTML element
- A React ref object
- An HTML tag name (e.g., “body”)
null to disable the portal
Where to insert the content relative to the destination element. Options:
"beforebegin" - Before the element
"afterbegin" - Inside, before first child
"beforeend" - Inside, after last child
"afterend" - After the element
Type Definitions
type ValidHtmlTags = keyof HTMLElementTagNameMap;
type InsertPosition = "beforebegin" | "afterbegin" | "beforeend" | "afterend";
type PortalProps = {
children: React.ReactNode;
insertPosition?: InsertPosition;
to: AnyString | HTMLElement | React.RefObject<HTMLElement> | ValidHtmlTags | null;
};
Usage Examples
Basic Portal to Body
function Modal({ isOpen, children }) {
if (!isOpen) return null;
return (
<Teleport to="body">
<div className="modal-overlay">
<div className="modal-content">
{children}
</div>
</div>
</Teleport>
);
}
Portal to Specific Element
// HTML: <div id="modal-root"></div>
function Notification({ message }) {
return (
<Teleport to="#modal-root">
<div className="notification">
{message}
</div>
</Teleport>
);
}
Using a Ref
function App() {
const portalRef = useRef(null);
return (
<>
<div ref={portalRef} className="portal-container" />
<Teleport to={portalRef}>
<Tooltip>Portaled content</Tooltip>
</Teleport>
</>
);
}
With Insert Position
function Header() {
return (
<header id="main-header">
<h1>My App</h1>
</header>
);
}
function Breadcrumbs() {
return (
<Teleport to="#main-header" insertPosition="beforeend">
<nav className="breadcrumbs">
<a href="/">Home</a> / <span>Current Page</span>
</nav>
</Teleport>
);
}
Conditional Portal
function Popover({ isOpen, target }) {
return (
<Teleport to={isOpen ? document.body : null}>
<div className="popover">
Popover content
</div>
</Teleport>
);
}
Multiple Portals
function App() {
return (
<>
<Teleport to="body">
<GlobalNotifications />
</Teleport>
<Teleport to="#sidebar-root">
<SidePanel />
</Teleport>
<Teleport to="#footer-root">
<ChatWidget />
</Teleport>
<MainContent />
</>
);
}
function Tooltip({ children, content, isVisible }) {
const triggerRef = useRef(null);
return (
<>
<span ref={triggerRef}>{children}</span>
{isVisible && (
<Teleport to="body">
<div className="tooltip">
{content}
</div>
</Teleport>
)}
</>
);
}
Modal Stack
function ModalProvider({ children }) {
return (
<>
{children}
<div id="modal-root" />
</>
);
}
function ConfirmDialog({ isOpen, onConfirm, onCancel }) {
if (!isOpen) return null;
return (
<Teleport to="#modal-root">
<div className="modal-backdrop">
<div className="dialog">
<p>Are you sure?</p>
<button onClick={onConfirm}>Yes</button>
<button onClick={onCancel}>No</button>
</div>
</div>
</Teleport>
);
}
Insert at Specific Position
// Insert before the main content
<Teleport to="#main-content" insertPosition="beforebegin">
<Announcement>Important message!</Announcement>
</Teleport>
// Insert as first child
<Teleport to="#container" insertPosition="afterbegin">
<Header />
</Teleport>
// Insert as last child
<Teleport to="#container" insertPosition="beforeend">
<Footer />
</Teleport>
// Insert after the element
<Teleport to="#main-content" insertPosition="afterend">
<RelatedContent />
</Teleport>
Client-Side Only
// The component automatically uses ClientGate internally
// This ensures it only renders on the client
function ServerSafeModal({ children }) {
return (
<Teleport to="body">
{children}
</Teleport>
);
}
// Works safely with SSR - won't cause hydration errors
Notes
- The component uses
ClientGate internally, making it safe for server-side rendering
- When
insertPosition is used, a temporary wrapper div is created and then unwrapped
- The wrapper div has
display: contents to avoid affecting layout
- Content is portaled using React’s
createPortal API
- The portal maintains React context and event bubbling through the component tree
- When
to is null, the portal is disabled and nothing is rendered
- CSS selector strings are resolved using
document.querySelector
- The component cleans up the temporary wrapper on unmount