
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
react-magic-portal
Advanced tools
A React component designed for browser extension development that provides react portal functionality with automatic anchor detection and DOM mutation monitoring.
$ pnpm add react-magic-portal
When developing browser extensions with React, you often need to inject React components into host web pages. However, the target mounting points in these pages are frequently dynamic - they may not exist when your extension loads, or they might be created and destroyed as users navigate and interact with the page.
Traditional React portals require the target DOM element to exist before rendering, which creates challenges in browser extension scenarios where:
React Magic Portal solves these challenges by automatically detecting when target elements appear or disappear in the DOM, ensuring your React components are always rendered in the right place at the right time.
last, first, before, and after positioningonMount and onUnmount callbacks for portal lifecycle managementimport MagicPortal from 'react-magic-portal'
function App() {
const [showTarget, setShowTarget] = useState(false)
return (
<div>
<button onClick={() => setShowTarget(!showTarget)}>Toggle Target</button>
{showTarget && <div id="anchor-target">Dynamic Target Element</div>}
{/* Portal will automatically mount/unmount based on target availability */}
<MagicPortal
anchor="#anchor-target"
onMount={() => console.log('Portal mounted')}
onUnmount={() => console.log('Portal unmounted')}
>
<div>This content follows the target element</div>
</MagicPortal>
</div>
)
}
import MagicPortal from 'react-magic-portal'
function App() {
return (
<div>
<div id="target">Target Element</div>
<MagicPortal anchor="#target" position="before">
<div>Content before target</div>
</MagicPortal>
<MagicPortal anchor="#target" position="first">
<div>Content at start of target</div>
</MagicPortal>
<MagicPortal anchor="#target" position="last">
<div>Content at end of target</div>
</MagicPortal>
<MagicPortal anchor="#target" position="after">
<div>Content after target</div>
</MagicPortal>
</div>
)
}
| Prop | Type | Default | Description |
|---|---|---|---|
anchor | string | (() => Element | null) | Element | React.RefObject<Element | null> | null | Required | The target element where the portal content will be rendered |
position | 'last' | 'first' | 'before' | 'after' | 'last' | Position relative to the anchor element |
root | Element | document.body | The root element to observe for DOM mutations |
children | React.ReactElement | null | undefined | A single React element to render in the portal (does not support Fragment) |
onMount | (anchor: Element, container: Element) => void | undefined | Callback fired when the portal is mounted |
onUnmount | (anchor: Element, container: Element) => void | undefined | Callback fired when the portal is unmounted |
<MagicPortal anchor="#anchor">
<div>Content</div>
</MagicPortal>
<MagicPortal anchor=".anchor">
<div>Content</div>
</MagicPortal>
const elementRef = useRef(null)
<div ref={elementRef}>Target</div>
<MagicPortal anchor={elementRef}>
<div>Content</div>
</MagicPortal>
<MagicPortal anchor={() => document.querySelector('.anchor')}>
<div>Content</div>
</MagicPortal>
<MagicPortal anchor={document.body}>
<div>Content</div>
</MagicPortal>
last (default)Adds content inside the anchor element at the end:
<div id="anchor">
Existing content
<!-- Portal content appears here -->
</div>
firstAdds content inside the anchor element at the beginning:
<div id="anchor">
<!-- Portal content appears here -->
Existing content
</div>
beforeAdds content as a sibling before the anchor element:
<!-- Portal content appears here -->
<div id="anchor">Existing content</div>
afterAdds content as a sibling after the anchor element:
<div id="anchor">Existing content</div>
<!-- Portal content appears here -->
When using React components as children, they must support ref forwarding to work correctly with MagicPortal. This is because MagicPortal needs to access the underlying DOM element to position it correctly.
interface MyComponentProps {
ref?: React.Ref<HTMLDivElement>
}
const MyComponent = ({ ref, ...props }: MyComponentProps) => {
return <div ref={ref}>My Component Content</div>
}
// This will work correctly
<MagicPortal anchor="#target">
<MyComponent />
</MagicPortal>
import { forwardRef } from 'react'
const MyComponent = forwardRef<HTMLDivElement>((props, ref) => {
return <div ref={ref}>My Component Content</div>
})
// This will work correctly
<MagicPortal anchor="#target">
<MyComponent />
</MagicPortal>
// Direct DOM elements always work
<MagicPortal anchor="#target">
<div>Direct DOM element</div>
</MagicPortal>
const MyComponent = () => {
return <div>My Component Content</div>
}
// This won't position correctly because ref cannot be passed to the component
<MagicPortal anchor="#target">
<MyComponent />
</MagicPortal>
const MyComponent = () => {
return <div>My Component Content</div>
}
// Wrap the component in a transparent DOM element
<MagicPortal anchor="#target">
<div style={{ display: 'contents' }}>
<MyComponent />
</div>
</MagicPortal>
MIT © molvqingtai
FAQs
React Portal with dynamic mounting support
We found that react-magic-portal demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.