https://github.com/richardscarrott/react-teleportal
Alternative React portal implementation, giving you control over portal rendering.
https://github.com/richardscarrott/react-teleportal
Last synced: 18 days ago
JSON representation
Alternative React portal implementation, giving you control over portal rendering.
- Host: GitHub
- URL: https://github.com/richardscarrott/react-teleportal
- Owner: richardscarrott
- License: mit
- Created: 2022-11-16T18:36:00.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2022-11-19T11:35:47.000Z (over 2 years ago)
- Last Synced: 2025-05-12T14:28:52.543Z (18 days ago)
- Language: TypeScript
- Size: 144 KB
- Stars: 6
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# React Teleportal
[](https://www.npmjs.com/package/react-teleportal)
[](https://github.com/richardscarrott/react-teleportal/actions/workflows/node.js.yml)
[](https://github.com/richardscarrott/react-teleportal/blob/main/LICENSE)Alternative [React Portal](https://reactjs.org/docs/portals.html) implementation, giving you control over portal rendering.
Primarily written to support uninterrupted exit animations when combined with components such as [`TransitionGroup`](https://reactcommunity.org/react-transition-group/transition-group) and [`AnimatePresence`](https://www.framer.com/docs/animate-presence/).
## Install
```
npm install react-teleportal
```## Examples
### React Teleportal x React Transition Group
https://codesandbox.io/s/react-teleportal-x-react-transition-group-k31d8p
### React Teleportal x Framer Motion
https://codesandbox.io/s/react-teleportal-x-framer-motion-766nu7
## Features
| Features | React Teleportal | ReactDOM.createPortal |
| --------------------------- | ---------------- | --------------------- |
| Custom Rendering | ✅ | ❌ |
| Context | ✅\* | ✅ |
| Server Side Rendering (SSR) | ⚠️† | ❌ |
| Multiple Portal Outlets | ❌‡ | ✅ |
| React Tree Event Bubbling | ❌ | ✅ |\* Although ``s in React Teleportal don't receive context from their own call site, they do receive context from the `` call site which means context from root providers will be available.
† Unlike `ReactDOM.createPortal`, React Teleportal doesn't depend on DOM APIs so the intention is to support SSR once a concurrent-safe solution has been found.
‡ React Teleportal doesn't currently support multiple portal outlets, but it would be trivial to add. For now it's been omitted because it would effectively become a "slot" library which, as a pattern, [doesn't play nicely with streaming SSR](https://github.com/cloudflare/react-gateway/issues/49).
## API
### Basic
```tsx
import React, { useState } from 'react';
import { PortalProvider, PortalOutlet, Portal } from 'react-teleportal';const App = () => {
const [show, setShow] = useState(true);
return (
setShow(!show)}>Toggle
{show ? (
<>I render in the PortalOutlet>
) : null}
);
};
```### Animations with [react-transition-group](https://codesandbox.io/s/react-teleportal-x-react-transition-group-k31d8p)
```tsx
import React, { useState, useRef } from 'react';
import { PortalProvider, PortalOutlet, Portal } from 'react-teleportal';
import { TransitionGroup, CSSTransition } from 'react-transition-group';const App = () => {
const [show, setShow] = useState(true);
const nodeRef = useRef(null);
return (
setShow(!show)}>Toggle
{show ? (
I render in the PortalOutlet
) : null}
{(children) => {children}}
);
};
```### Animations with [framer-motion](https://codesandbox.io/s/react-teleportal-x-framer-motion-766nu7)
```tsx
import React, { useState } from 'react';
import { PortalProvider, PortalOutlet, Portal } from 'react-teleportal';
import { AnimatePresence, motion } from 'framer-motion';const App = () => {
const [show, setShow] = useState(true);
return (
setShow(!show)}>Toggle
{show ? (
I render in the PortalOutlet
) : null}
{(children) => {children}}
);
};
```## FAQ
### Does React Teleportal support SSR?
React Teleportal won't blow up on the server, but ``s won't be rendered to HTML server side and instead will be rendered once on the client.
The intention is to eventually find a concurrent-safe SSR solution.
### Can I have multiple _named_ ``s?
No not currently. React Teleportal intends to eventually support SSR & treating this as a "slot" library makes SSR less viable.
React Gateway is a good example of the "slot" pattern and [how it can easily fail if misused](https://github.com/cloudflare/react-gateway/issues/49).
```tsx
import { GatewayProvider, GatewayDest, Gateway } from 'react-gateway';const App = () => {
return (
SSR will fail to render this as the "header-slot" has already rendered
(and if streaming, the html has potentially already been flushed to
the client).
);
};
```React Teleportal is therefore stricter and only allows a single `` (or `` in React Teleportal terminology) which should be rendered at the _bottom_ of the root component.
### How do I manage stacking order?
It's recommended to avoid z-index and treat your `` similar to the DOM's [Top Layer](https://developer.chrome.com/blog/what-is-the-top-layer/) whereby the most recently ~~opened~~ mounted `` is rendered last and therefore naturally stacked on top.
### Why do I need to add a `key` to the `` child when animating?
The collective `` children are ultimately rendered as `children` of the `` which means React is rendering a variable length array of elements which [requires a `key`](https://beta.reactjs.org/learn/rendering-lists).
It's recommended to just statically include a `uuid` or similar at the call site of each distinct `` child to ensure it remains unique as your app grows.
```tsx
Hello World```
> NOTE: If you're not animating (i.e. if the `` unmounts the child immediately), then you can omit the key as React Teleportal is able to assign a key on your behalf.
## License
[MIT](LICENSE)