Skip to content
Utilities & Providers

Portal

client6 kB

Renders its children somewhere else in the DOM, and waits for the client to do it.

@stellaria/nebula-webPortalProps

Preview

There is nothing to look at here: Portal renders the same children you gave it, only somewhere else in the document. What it changes is where they land, and that does not show up in a preview.

What it is for

A dropdown inside a card with overflow: hidden gets clipped. A tooltip inside a stacking context with a transform paints under the next section. Neither is a styling bug: both elements are trapped by an ancestor. Portal moves them out — to document.body by default, or to whatever you pass as target.

It does not portal until it mounts

Server and client render the same tree first, and only after mounting does the content move. That is deliberate: portaling during the server pass produces markup the client cannot match, which is a hydration mismatch in Next. The cost is one frame in its original position; the alternative is an error in the console and a subtree React rebuilds from scratch.

disabled turns it off and renders in place — useful when the same component is used both inside and outside a clipping ancestor.

You rarely mount it yourself

Every overlay in the catalogue already portals: Modal, Drawer, Popover, Menu, Tooltip, Lightbox. Reach for Portal when you build a surface the catalogue does not cover.

Props

3
PropTypeDefault

children

What renders at the other end of the portal. Nothing reaches the DOM on the first render: the portal waits for the client mount effect, so the server output is empty and there is no hydration mismatch. Anything that must be in the server HTML does not belong here.

ReactNode

disabled

Renders the children in place instead, which keeps them subject to the ancestors' `overflow` and stacking context. It is also the only branch that renders on the server.

booleanfalse

target

Where to portal to, as an element or as a CSS selector resolved against the document on every render. A selector that matches nothing is not an error: it falls back to the container of the surrounding React Aria portal provider, and to `document.body` when there is none.

string | Element | null