Overview
usePortal is a React hook that creates a dedicated DOM element (portal) for rendering content like modals, tooltips, and overlays outside the normal component hierarchy. It automatically manages the portal’s lifecycle and cleanup.
Import
import { usePortal } from '@dynamic-framework/ui-react';
Signature
function usePortal(portalName: string): {
created: boolean;
}
Parameters
Unique identifier for the portal element. This becomes the DOM element’s id attribute.
Return Value
Returns an object with the following property:
Indicates whether the portal DOM element has been successfully created and mounted to the document body.
Behavior
When the hook is called:
- Cleanup: Removes any existing portal element with the same
portalName
- Creation: Creates a new
div element with:
id set to portalName
className set to d-portal
- Mounting: Appends the portal element to
document.body
- State Update: Sets
created to true once the portal is mounted
The portal is created once when the component mounts and is cleaned up when the component unmounts.
Usage Examples
Basic Portal Creation
import { usePortal } from '@dynamic-framework/ui-react';
function MyModal() {
const { created } = usePortal('my-modal-portal');
if (!created) {
return null;
}
return createPortal(
<div className="modal">
<h2>Modal Content</h2>
</div>,
document.getElementById('my-modal-portal')
);
}
With DPortalContext
The usePortal hook is used internally by DPortalContext to create portal containers for overlays:
import { DPortalContext, usePortal } from '@dynamic-framework/ui-react';
function App() {
const { created } = usePortal('app-portal');
if (!created) {
return <div>Loading...</div>;
}
return (
<DPortalContext.Provider
config={{
portalName: 'app-portal',
}}
>
{/* Your app content */}
</DPortalContext.Provider>
);
}
Multiple Portals
You can create multiple portals for different types of overlays:
function AppLayout() {
const modalPortal = usePortal('modal-portal');
const tooltipPortal = usePortal('tooltip-portal');
const toastPortal = usePortal('toast-portal');
const allPortalsReady = modalPortal.created
&& tooltipPortal.created
&& toastPortal.created;
if (!allPortalsReady) {
return <div>Initializing...</div>;
}
return (
<div>
{/* Render your app */}
</div>
);
}
Conditional Portal
Create a portal only when needed:
function ConditionalOverlay({ showOverlay }) {
const { created } = usePortal('conditional-portal');
if (!showOverlay) {
return null;
}
if (!created) {
return <div>Loading overlay...</div>;
}
return createPortal(
<div className="overlay">Overlay content</div>,
document.getElementById('conditional-portal')
);
}
Implementation Details
The hook uses useEffect to manage the portal lifecycle:
- Mount: Creates the portal element and appends it to
document.body
- Cleanup: Automatically removes the portal when the component unmounts
- Uniqueness: If a portal with the same name already exists, it’s removed before creating a new one
DOM Structure
When created, the portal element has this structure:
<body>
<!-- Your app root -->
<div id="root">...</div>
<!-- Portal element created by usePortal -->
<div id="your-portal-name" class="d-portal">
<!-- Content rendered via createPortal -->
</div>
</body>
Best Practices
Use descriptive portal names that clearly indicate their purpose (e.g., 'modal-portal', 'tooltip-portal', 'notification-portal').
Ensure portal names are unique across your application to avoid conflicts and unexpected behavior.
The portal element is automatically cleaned up when the component unmounts, so you don’t need to manually remove it.
- DPortalContext - Context for managing portal-based overlays
- DModal - Modal component that uses portals
- DTooltip - Tooltip component that uses portals