@radix-ui/react-portal vs react-portal
Rendering Components Outside the DOM Hierarchy in React
@radix-ui/react-portalreact-portal

Rendering Components Outside the DOM Hierarchy in React

@radix-ui/react-portal and react-portal are both libraries designed to render React components into a DOM node that exists outside the parent component's DOM hierarchy. This is essential for building modals, tooltips, and popovers that need to escape overflow-hidden containers or z-index stacking contexts. @radix-ui/react-portal is part of the modern Radix UI primitive ecosystem, offering unstyled, accessible components that integrate tightly with React 18+ features. react-portal is a legacy standalone library that pioneered this pattern but has seen less active development in recent years compared to the Radix ecosystem.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
@radix-ui/react-portal019,23111.9 kB348a month agoMIT
react-portal02,15239.2 kB162 years agoMIT

@radix-ui/react-portal vs react-portal: Architecture and Maintenance Compared

Both @radix-ui/react-portal and react-portal solve the same fundamental problem: rendering children into a DOM node outside the current component tree. This is critical for UI elements like modals, dropdowns, and toast notifications that must visually break out of their container's clipping or stacking context. However, they differ significantly in maintenance status, API design, and ecosystem integration.

🛠️ Maintenance and React Version Support

@radix-ui/react-portal is actively maintained as part of the Radix UI suite.

  • It receives regular updates to support the latest React versions, including React 18 and 19.
  • It handles concurrent rendering and strict mode correctly without warnings.
// @radix-ui/react-portal: Modern React support
import * as Portal from '@radix-ui/react-portal';

function Modal() {
  return (
    <Portal.Root>
      <div className="modal-content">Hello</div>
    </Portal.Root>
  );
}

react-portal is a legacy library with infrequent updates.

  • It may require workarounds or forks to work correctly with React 18's strict mode.
  • Development activity has slowed significantly compared to modern alternatives.
// react-portal: Legacy implementation
import Portal from 'react-portal';

function Modal() {
  return (
    <Portal isOpened={true}>
      <div className="modal-content">Hello</div>
    </Portal>
  );
}

🧩 API Design and Usage

@radix-ui/react-portal uses a declarative component API with named exports.

  • You wrap content in <Portal.Root> to render it at the document body by default.
  • It supports a container prop to specify a custom target node.
// @radix-ui/react-portal: Declarative API
import * as Portal from '@radix-ui/react-portal';

function Tooltip() {
  return (
    <Portal.Root container={document.getElementById('tooltip-root')}>
      <span>Tooltip content</span>
    </Portal.Root>
  );
}

react-portal uses a single default export component with props.

  • You control visibility via the isOpened prop.
  • It also supports a node prop to define the target container.
// react-portal: Prop-based API
import Portal from 'react-portal';

function Tooltip() {
  return (
    <Portal isOpened={true} node={document.getElementById('tooltip-root')}>
      <span>Tooltip content</span>
    </Portal>
  );
}

📘 TypeScript and Developer Experience

@radix-ui/react-portal is built with TypeScript first.

  • Types are included out of the box and are well-maintained.
  • IDE autocomplete works seamlessly for all props and events.
// @radix-ui/react-portal: Full TypeScript support
import * as Portal from '@radix-ui/react-portal';

// Props are fully typed
<Portal.Root className="custom-class">
  {children}
</Portal.Root>

react-portal has community-maintained types or older definitions.

  • You may need to install @types/react-portal separately.
  • Type definitions might not cover all edge cases or recent React changes.
// react-portal: External types required
import Portal from 'react-portal';
// May require: npm install --save-dev @types/react-portal

<Portal isOpened={true}>
  {children}
</Portal>

🌐 Ecosystem Integration

@radix-ui/react-portal integrates with other Radix primitives.

  • It is designed to work with Radix dialogs, popovers, and tooltips.
  • Shared context and styling patterns make it ideal for design systems.
// @radix-ui/react-portal: Part of a larger system
import * as Dialog from '@radix-ui/react-dialog';
import * as Portal from '@radix-ui/react-portal';

// Used internally by Dialog, but available for custom composition
<Dialog.Portal>
  <Dialog.Overlay />
  <Dialog.Content />
</Dialog.Portal>

react-portal is a standalone solution.

  • It does not assume any specific UI library or design system.
  • Good for isolated use cases but lacks deep integration features.
// react-portal: Standalone usage
import Portal from 'react-portal';

// No built-in integration with other UI libraries
<Portal isOpened={isOpen}>
  <CustomModal />
</Portal>

⚠️ Deprecation and Risk

@radix-ui/react-portal is safe for long-term use.

  • Backed by a dedicated team and corporate sponsors.
  • No deprecation warnings currently exist.
// @radix-ui/react-portal: Future-proof
// No expected breaking changes in the near term

react-portal carries higher maintenance risk.

  • While not officially deprecated, it is considered legacy by many.
  • New projects should evaluate modern alternatives before adopting.
// react-portal: Evaluate alternatives
// Consider migration path to Radix or native React.createPortal

🤝 Similarities: Shared Ground

Despite their differences, both libraries share core functionality and goals.

1. 🚪 DOM Hierarchy Escape

  • Both allow rendering children into a different DOM node.
  • Useful for avoiding overflow: hidden or z-index issues.
// Both solve this problem
// @radix-ui/react-portal
<Portal.Root>{content}</Portal.Root>

// react-portal
<Portal isOpened>{content}</Portal>

2. ⚛️ React Component Model

  • Both use React components to manage the portal lifecycle.
  • They handle mounting and unmounting automatically.
// Both use standard React patterns
function App() {
  const [open, setOpen] = useState(false);
  return open && <PortalComponent />;
}

3. 🎯 Custom Container Support

  • Both allow specifying a target DOM element other than body.
  • Essential for Shadow DOM or specific layout requirements.
// @radix-ui/react-portal
<Portal.Root container={ref.current} />

// react-portal
<Portal node={ref.current} />

📊 Summary: Key Differences

Feature@radix-ui/react-portalreact-portal
Maintenance✅ Active, Regular Updates⚠️ Legacy, Infrequent Updates
React 18 Support✅ Full Support⚠️ May Require Workarounds
TypeScript✅ Built-in, First-class⚠️ Community Types
Ecosystem🧩 Part of Radix UI Primitives🧍 Standalone
API Style🧱 Named Exports (Portal.Root)🧱 Default Export (Portal)
Recommendation✅ Preferred for New Projects⚠️ Legacy Maintenance Only

💡 The Big Picture

@radix-ui/react-portal is the modern standard 🏆 — it offers better TypeScript support, active maintenance, and seamless integration with contemporary React features. It is the clear choice for building robust, accessible design systems.

react-portal is a legacy tool 🕰️ — it served the community well for many years but is now overshadowed by more integrated solutions. Use it only if you are maintaining existing code that depends on it.

Final Thought: While react-portal pioneered the pattern, @radix-ui/react-portal represents the current best practice. For new development, prioritize libraries that align with the modern React ecosystem to reduce technical debt over time.

How to Choose: @radix-ui/react-portal vs react-portal

  • @radix-ui/react-portal:

    Choose @radix-ui/react-portal for new projects, especially if you are already using Radix UI primitives or require strict accessibility compliance. It is actively maintained, fully typed with TypeScript, and designed to work seamlessly with React 18's concurrent features. This is the standard choice for modern design systems and component libraries.

  • react-portal:

    Choose react-portal only if you are maintaining a legacy codebase that already depends on it and migration costs are too high. It is generally not recommended for new development due to slower update cycles and less integration with modern React ecosystems. Consider migrating to @radix-ui/react-portal for better long-term support.

README for @radix-ui/react-portal

react-portal

View docs here.