# Portal

- Page: https://jiguang132.com/resources/mantine/docs/portal
- Resource: Mantine Core (https://jiguang132.com/resources/mantine.md)
- All guides: https://jiguang132.com/resources/mantine/docs.md

Install: `npm install @mantine/core@9.7.1 @mantine/hooks@9.7.1`

## Version and compatibility

Pinned Mantine Core 9.7.1 requires React and React DOM `^19.2.0` and matching `@mantine/hooks@9.7.1`, from the installed npm package's peerDependencies. Do not force it into React 18 or another incompatible version. Explain upgrade impact and agree on a plan with the project owner; do not hide conflicts with --force/--legacy-peer-deps. The native Provider enables `theme.respectReducedMotion` and uses `forceColorScheme` for light/dark.

## Use case

Render children outside their normal DOM parent.

## Native props used by this example

These props are extracted from the local typechecked JSX and grouped by their owning native component. This is not an exhaustive prop list; see pinned source signatures and inheritance below.

This minimal example passes children only; no additional props are invented. Optional props are in the source reference.

## Interaction and state checks

Current scenarios: Default. Check actual behavior after selecting supported disabled/error/read-only scenarios; components without those native states do not receive invented universal props. Verify keyboard focus and exits, then connect changed values through the native callback signature.

## Business integration boundary

The content is rendered outside the normal parent but still inside its iframe document. Portals cannot cross the isolation boundary.

## Host setup

Install pinned @mantine/core and @mantine/hooks, import @mantine/core/styles.css at the entry and use MantineProvider. The example's theme/variant are JGuang-authored host props, not universal native component APIs; forceColorScheme synchronizes the app theme. Native implementation source is a reading reference: use npm exports rather than copying internal engines. This batch covers Core, not dates/charts/forms extension packages. Detailed upstream prose remains English.


## Runnable usage

```tsx
import { useState } from 'react';
import * as M from '@mantine/core';
import '@mantine/core/styles.css';


function ComponentPreview({ variant = 'Default' }: { variant?: string }) {
const content = <M.Text>Build something beautiful / 构建美好的界面</M.Text>;
return <M.Portal>{content}</M.Portal>;
}
export default function Example({ variant = 'Default', theme = 'light' }: { variant?: string; theme?: 'light' | 'dark' }) {
return <M.MantineProvider forceColorScheme={theme} theme={{ respectReducedMotion: true }}><ComponentPreview variant={variant} /></M.MantineProvider>;
}

```


## Preview states

Default

The example uses the native Mantine API. For supported input demos, change the local variant to Disabled, Invalid or Read only; these are example labels, not new component props. Keep the documented data, controlled values, stores and compound children when adapting the example.



## Usage

Portal is a wrapper component for the [ReactDOM.createPortal](https://reactjs.org/docs/portals.html) API.
Render any component or element at the end of `document.body` or at a given element. The [Modal](/core/modal/) and [Drawer](/core/drawer/) components are wrapped in Portal by default.

Use Portal to render a component or an element at a different place (defaults to the end of `document.body`).
Portal is useful when you want to prevent parent styles from interfering with children.
Usually all these styles are related to `position` and `z-index` properties,
and portals are used for components with fixed position, for example, modals.

```tsx
import { useState } from 'react';
import { Portal } from '@mantine/core';

function Demo() {
  const [opened, setOpened] = useState(false);

  return (
    <main style={{ position: 'relative', zIndex: 1 }}>
      {opened && (
        <Portal>
          <div>Your modal content</div>
        </Portal>
      )}

      <button onClick={() => setOpened(true)} type="button">
        Open modal
      </button>
    </main>
  );
}
```

In the example above, the div element is rendered outside of the parent main (before the closing body tag),
but still receives the `opened` and `onClose` props. The element will not be affected by the parent z-index.

## Reuse target node

By default, Portal reuses the same target node for all instances (`reuseTargetNode={true}`).
To create a new target node for each instance, set `reuseTargetNode={false}`. In the following
example, all three paragraphs will be rendered in separate target nodes:

```tsx
import { Portal } from '@mantine/core';

function Demo() {
  return (
    <>
      <Portal reuseTargetNode={false}>
        <p>First</p>
      </Portal>

      <Portal reuseTargetNode={false}>
        <p>Second</p>
      </Portal>

      <Portal reuseTargetNode={false}>
        <p>Third</p>
      </Portal>
    </>
  );
}
```

## Specify target DOM node

You can specify the DOM node where the portal will be rendered by passing the `target` prop:

```tsx
import { Portal } from '@mantine/core';

const container = document.createElement('div');
document.body.appendChild(container);

function Demo() {
  return <Portal target={container}>My portal</Portal>;
}
```

Alternatively, you can specify a selector to render the portal in an existing element:

```tsx
import { Portal } from '@mantine/core';

function Demo() {
  return <Portal target="#portal-container">My portal</Portal>;
}
```

If you don't specify the target element, a new one will be created and appended to the `document.body` for each Portal component.

## Server side rendering

`createPortal` is not supported during server-side rendering.
All components inside Portal are rendered only after the application was mounted to the DOM.

## OptionalPortal component

The `OptionalPortal` component lets you configure whether children should be rendered in `Portal`.
It accepts the same props as the `Portal` component:

```tsx
import { OptionalPortal } from '@mantine/core';

function Demo() {
  return (
    <>
      <OptionalPortal withinPortal>
        This text is rendered in Portal
      </OptionalPortal>
      <OptionalPortal withinPortal={false}>
        This text is rendered as regular child
      </OptionalPortal>
    </>
  );
}
```


## Source-backed parameter reference

Implementation signatures and types are generated from the pinned local source. Optional props, native inherited types, union branches and never exclusions are preserved. A forwardRef implementation's ref is a React reference, not an additional business prop.


```ts
Portal(props)
```



```ts
export interface BasePortalProps extends React.ComponentProps<'div'> {
  /**
   * Target element where portal should be rendered. Accepts:
   * - HTMLElement: Renders portal inside this element
   * - string: CSS selector - renders inside first matching element
   * - undefined: Uses shared portal node or creates new one based on `reuseTargetNode`
   *
   * Note: If selector doesn't match any element, portal will not render
   */
  target?: HTMLElement | string;

  /**
   * When true and target is not specified, all Portal instances share a single
   * container node appended to document.body. When false, each Portal creates
   * its own container node.
   *
   * Has no effect when target is specified.
   *
   * @default true
   */
  reuseTargetNode?: boolean;
}

export interface PortalProps extends BasePortalProps {
  /** Content to render inside the portal */
  children: React.ReactNode;
}

export type PortalFactory = Factory<{
  props: PortalProps;
  ref: HTMLDivElement;
}>;
```


### Native and external types

External types remain defined by React or native dependencies, not manually expanded into guessed props. The installed version's TypeScript definitions are authoritative.


```ts
Factory<{
  props: PortalProps;
  ref: HTMLDivElement;
}>
React.ComponentProps<'div'>
HTMLElement
React.ReactNode
HTMLDivElement
```

---

Index of all JGuang resources: https://jiguang132.com/llms.txt
