Socket
Book a DemoInstallSign in
Socket

@bento/portal

Package Overview
Dependencies
Maintainers
4
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bento/portal

Portal component primitive - render children into a target DOM container

latest
Source
npmnpm
Version
0.1.1
Version published
Maintainers
4
Created
Source

Portal

The @bento/portal package exports the Portal component, which renders children into a target DOM container outside the normal React component hierarchy. Portal solves common UI challenges like z-index conflicts, clipping issues, and overlay stacking by rendering content to document.body or a custom container.

Portal integrates seamlessly with React ARIA's UNSAFE_PortalProvider while remaining fully independent and functional without it.

Use Cases

Portal is essential for UI elements that need to escape their parent container's boundaries:

  • Overlays and Modals: Prevent clipping and z-index conflicts
  • Dropdown Menus: Render above all other content regardless of parent constraints
  • Tooltips: Position freely without overflow hidden issues
  • Toast Notifications: Display at the application level
  • Popovers and Dialogs: Ensure proper stacking and positioning

Installation

npm install --save @bento/portal

Props

The @bento/portal package exports the Portal component:

<Source language='tsx' code={ BasicExample } />

The following properties are available to be used on the Portal component:

PropTypeRequiredDescription
containerElementNoThe container to render the portal content into.
If not provided, Portal will check for React ARIA's PortalProvider,
and fall back to document.body.
mountedbooleanNoShould the portal content be mounted.
Set to false by default for server-side rendering compatibility.
Portal will not render children if not mounted.
childrenReactNode | ((data: { props: { mounted?: boolean; }; }) => ReactNode)YesThe content to render inside the portal.
Can be a React node or a render prop function that receives props.
slotstringNoA named part of a component that can be customized. This is implemented by the consuming component.
The exposed slot names of a component are available in the components documentation.
slotsRecord<string, object | Function>NoAn object that contains the customizations for the slots.
The main way you interact with the slot system as a consumer.

Examples

Basic

Basic portal usage that renders content to document.body:

<Source language='tsx' code={ BasicExample } />

Custom Container

Portal can render to a custom container instead of document.body. This is useful when you need to control the exact DOM location where portal content appears:

<Source language='tsx' code={ CustomContainerExample } />

React ARIA Integration

Portal optionally integrates with React ARIA's UNSAFE_PortalProvider to provide consistent portal container management across your application. This example demonstrates how Portal automatically detects and uses the PortalProvider's container:

<Source language='tsx' code={ PortalProviderExample } />

Container priority:

  • Explicit container prop (highest priority)
  • React ARIA's UNSAFE_PortalProvider container (via useUNSAFE_PortalContext)
  • document.body (fallback)

Benefits:

  • Stacking context: All overlays share the same stacking context
  • Custom location: Control where overlays render in DOM
  • Multiple overlays: Proper stacking when multiple portals/overlays are open
  • React ARIA compatibility: Works seamlessly with React ARIA components
  • Graceful degradation: Works without React ARIA installed

SSR Safety

Portal is SSR-safe and will not render content on the server. The mounted prop should be set to true only after the component has mounted on the client:

function MyComponent() {
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    setMounted(true);
  }, []);

  return (
    <Portal mounted={mounted}>
      <Container>Content</Container>
    </Portal>
  );
}

Accessibility

Portal is designed with accessibility in mind:

  • Semantic HTML: Portal doesn't interfere with semantic HTML structure
  • Screen Reader Support: Content rendered through Portal remains accessible to screen readers
  • Focus Management: Portal doesn't trap or redirect focus - implement your own focus management as needed for modals/dialogs
  • Keyboard Navigation: Portal preserves keyboard navigation of its content
  • ARIA Support: All ARIA attributes applied to portal content are preserved

Note: Portal is a rendering utility and doesn't provide built-in focus *trapping or modal behavior. For accessible modals and dialogs, combine Portal *with proper focus management and ARIA attributes.

Data Attributes

Portal applies the following data attributes to portal content:

AttributeDescriptionExample Values
data-portalMarks content rendered via portal"true"
data-mountedWhether portal content has mounted"true" / "false"

Customization

Portal is a rendering utility component that doesn't render its own DOM elements. Instead, it renders children into a target container using React's createPortal. Because of this, Portal doesn't introduce internal slots like other Bento components.

Slots

Portal is created using the @bento/slots package via withSlots('BentoPortal', ...), which means it supports the standard slot and slots props for integration with parent components. However, Portal itself doesn't define any internal slot assignments since it acts as a transparent rendering boundary.

See the @bento/slots package for more information on how to use the slot and slots properties.

Styling

Portal applies data attributes to the children it renders, making it possible to style portal content based on its state. Since Portal doesn't render wrapper elements, you should apply className or style props directly to the children you pass to Portal.

The data attributes Portal applies can be used in your CSS selectors:

/* Target all portal content */
[data-portal="true"] {
  /* Styles for content rendered through Portal */
}

/* Target mounted portal content */
[data-portal="true"][data-mounted="true"] {
  /* Styles for mounted portal content */
  animation: fadeIn 200ms ease-in;
}

When using Portal with other Bento components like Container, you can apply styling through those components:

<Portal mounted={mounted}>
  <Container className="my-overlay">
    <Text>Styled portal content</Text>
  </Container>
</Portal>

The data attributes will be applied to the Container element, allowing you to target it:

.my-overlay[data-portal="true"] {
  /* Your custom styles */
}

Keywords

bento

FAQs

Package last updated on 18 Dec 2025

Did you know?

Socket

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.

Install

Related posts