# @fluentui/react-portal

> A utility component that creates portals compatible with Fluent UI

Latest version **9.8.16** (published 2026-09-21) · MIT license · 0 weekly downloads

## Install

```sh
npm install @fluentui/react-portal
pnpm add @fluentui/react-portal
yarn add @fluentui/react-portal
bun add @fluentui/react-portal
```

## Health

**Score 70/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; recently updated; high maintenance score; popular repo.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 9.8.16 |
| Published | 2026-09-21 |
| First published | 2021-04-21 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 5 |
| Unpacked size | 223.9 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 20293 |
| Maintainers | uifabricteam, uifrnbot, microsoft1es, microsoft-oss-releases |

## Links

- npm: https://www.npmjs.com/package/@fluentui/react-portal
- Repository: https://github.com/microsoft/fluentui
- Homepage: https://github.com/microsoft/fluentui#readme
- Issues: https://github.com/microsoft/fluentui/issues
- npm.io page: https://npm.io/package/@fluentui/react-portal

## Dependencies (5)

- [@swc/helpers](https://npm.io/package/@swc/helpers.md) ^0.5.1
- [@griffel/react](https://npm.io/package/@griffel/react.md) ^1.5.32
- [@fluentui/react-tabster](https://npm.io/package/@fluentui/react-tabster.md) ^9.26.18
- [@fluentui/react-utilities](https://npm.io/package/@fluentui/react-utilities.md) ^9.26.7
- [@fluentui/react-shared-contexts](https://npm.io/package/@fluentui/react-shared-contexts.md) ^9.26.4

## Recent versions

- 9.8.16 (latest) — 2026-09-21
- 0.0.0-nightly-20260928-0404.1 (nightly) — 2026-09-28
- 9.74.5-experimental.tabster-v9.20260804-bb909442fe.0 (experimental) — 2026-08-04
- 9.0.0-rc.14 (rc) — 2022-06-21
- 9.0.0-beta.5 (beta) — 2021-11-25
- 9.0.0-alpha.61 (alpha) — 2021-10-05
- 0.0.0-nightly-20260925-0403.1 — 2026-09-25
- 0.0.0-nightly-20260924-0403.1 — 2026-09-24
- 0.0.0-nightly-20260923-0404.1 — 2026-09-23
- 0.0.0-nightly-20260922-0403.1 — 2026-09-22
- 0.0.0-nightly-20260917-0408.1 — 2026-09-17
- 0.0.0-nightly-20260916-0409.1 — 2026-09-16
- 0.0.0-nightly-20260915-0407.1 — 2026-09-15
- 0.0.0-nightly-20260914-0407.1 — 2026-09-14
- 0.0.0-nightly-20260910-0408.1 — 2026-09-10
- … 1390 more at https://npm.io/package/@fluentui/react-portal/versions

## README

# @fluentui/react-portal

**React Portal components for [Fluent UI React](https://react.fluentui.dev)**

This package contains the `Portal` component, which allow consumers to render [React portals](https://reactjs.org/docs/portals.html) with Fluent styling and RTL awareness.

## Usage

### Portal

`Portal` can be used as standalone with any part of a Fluent app. The component should be under a `FluentProvider` in the tree to make sure that proper theming and RTL handling is available.

By default `Portal` will render content to `document body`

```tsx
<FluentProvider>
  <Portal>Content rendered by default to Fluent's document.body</Portal>
</FluentProvider>
```

The mount location of the portal can be customized

```tsx
const node = document.getElementById('customNode');

<Portal mountNode={node}>Render to a custom node in DOM</Portal>;
```

### Styling

`Portal` renders React children directly to the default/configured DOM node. Therefore styling should be applied to the `children` by users directly.

### Virtual parents

Out of order DOM elements can be problematic when using 'click outside' event listeners since you cannot rely on `element.contains(event.target)` because the `Portal` elements are out of DOM order.

```tsx

const outerButtonRef = React.useRef();
const innerButtonRef = React.useRef();


<Portal>
  <div>
    <button ref={outerButtonRef}> Outer button </button>
    <Portal>
      <div>
        <button ref={innerButtonRef}> Inner button </button>
      </div>
    </Portal>
  </div>
</Portal>

// DOM output
<div>
  <button>Outer button</button>
</div>

<div>
  <button>Inner button</button>
</div>

// Let's add an event listener to 'dismss' the outer portal when clicked outside
// ⚠⚠⚠ This will always be called when clicking on the inner button
document.addEventListener((event) => {
  if (outerButtonRef.current.contains(event.target)) {
    dismissOuterPortal();
  }
})
```

When the above case is not required, using `element.contains` is perfectly fine. But nested cases should still be handled appropriately. We do this using the concept of `virtual parents`

`Portal` will make public 2 utilities that will only be used in cases where the user needs to know if an out of order DOM element will need to be used or not.

- `setVirtualParent` - sets virtual parent. Portal uses this already internally.
- `elementContains` - similar to `element.contains` but uses the virtual hierarchy as reference

Below shows what a virtual parent is

```tsx
// Setting a virtual parent

const parent = document.getElementById('parent');
const child = document.getElementById('child');

child._virtual.parent = parent;
```

`Portals` will render a hidden span that will be the virtual parent, by nesting portals virtual parens will also be nested so that `elementContains` will work predictably.

```tsx
<FluentProvider>
  <Portal id="portal-1" />
  <Portal id="portal-2" />
</FluentProvider>
```

DOM output:

```tsx
<body>
  <div>
    {/* Virtual parent for portal*/}
    <span aria-hidden />
    {/* Virtual parent for portal*/}
    <span aria-hidden />
  </div>

  <div id="portal-1" class="theme-provider-0">
    {children}
  </div>
  <div id="portal-2" class="theme-provider-0">
    {children}
  </div>
</body>
```

```tsx
<FluentProvider>
  <Portal id="portal-1">
    <Portal id="portal-2" />
  </Portal>
</FluentProvider>
```

DOM output:

```tsx
<body>
  <div>
    {/* Virtual parent for outer portal*/}
    <span aria-hidden></span>
  </div>

  <div id="portal-1" class="theme-provider-0">
    {/* Virtual parent for inner portal*/}
    <span aria-hidden />
    {children}
  </div>
  <div id="portal-2" class="theme-provider-0">
    {children}
  </div>
</body>
```

---
_Source: https://npm.io/package/@fluentui/react-portal · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
