React Teleporter
React Teleporter is a library designed for seamlessly moving or "teleporting" React components within the same React component tree. Unlike standard React Portals, which can render children into a different DOM node outside the current DOM hierarchy, `react-teleporter` maintains the logical connection within the same React tree. This distinction simplifies state and context management, as components remain within their original React context, making it ideal for managing complex layouts where content needs to appear in a different visual location than where it's defined. Inspired by the configuration philosophy of `react-helmet`, it allows for configuring parts of an application from a separate, perhaps deeply nested, location. The current stable version is 3.2.0, with regular minor and patch releases to support new React versions (currently up to React 19) and add features like `function as children` for `Source` components. Major versions, such as v3.0.0, introduce significant breaking changes, notably the transition to an ESM-only distribution. The library exports `createTeleporter`, which generates a `Source` and `Target` pair, enabling content defined within a `Source` component to be rendered at the `Target`'s designated position.
Common errors
-
ReferenceError: require is not defined
cause `react-teleporter` is ESM-only since v3.0.0, and you are attempting to use CommonJS `require()` syntax.fixChange your import statement from `const { createTeleporter } = require('react-teleporter');` to `import { createTeleporter } from 'react-teleporter';`. -
TypeScript errors related to 'createTeleporter' or its return types.
cause Your project's `react-teleporter` types are outdated or incompatible with the library version, most commonly seen when migrating to v3.0.0.fixEnsure you are using `react-teleporter@^3.0.0` or later and update your TypeScript configuration and code to reflect the new type definitions. Run `npm install react-teleporter@latest` or `yarn add react-teleporter@latest`. -
Console warning: 'React-teleporter: Only one Source is allowed for this Teleporter. Ignoring new Source.' (or similar)
cause You are attempting to render multiple `<Teleporter.Source>` components for a single `Teleporter` instance without enabling the `multiSources` option.fixInitialize your teleporter with `multiSources: true`: `const MyTeleporter = createTeleporter({ multiSources: true });`.
Warnings
- breaking Starting with v3.0.0, `react-teleporter` is distributed as ESM-only. Projects must use ES module import syntax (`import`) instead of CommonJS `require()`.
- breaking Type definitions were significantly changed in v3.0.0 to align with the modernized project structure and ESM-only distribution.
- gotcha `react-teleporter` uses React Portals under the hood when rendering to a target element. Be cautious when specifying the `as` prop on `Target` with a custom DOM element, as incorrect usage with refs might lead to unexpected behavior or compatibility issues.
- gotcha By default, a `Teleporter` instance only allows a single `Source` component to be active at a time. If multiple `Source` components are rendered, only the latest one will be displayed, or a warning might be issued.
- gotcha The `Source` component can accept a function as children, providing access to the `Target` element. This feature was introduced in v3.1.0.
Install
-
npm install react-teleporter -
yarn add react-teleporter -
pnpm add react-teleporter
Imports
- createTeleporter
const { createTeleporter } = require('react-teleporter')import { createTeleporter } from 'react-teleporter' - Teleporter
import { Teleporter } from 'react-teleporter'import Teleporter from 'react-teleporter'
- Teleporter.Source
const MyTeleporter = createTeleporter(); <MyTeleporter.Source>...</MyTeleporter.Source>
- Teleporter.Target
const MyTeleporter = createTeleporter(); <MyTeleporter.Target />
Quickstart
import { createTeleporter } from "react-teleporter";
import React from "react";
import ReactDOM from "react-dom/client";
const StatusBar = createTeleporter();
function Header() {
return (
<header style={{ borderBottom: "1px solid #ccc", padding: "10px" }}>
<h2>My App Header</h2>
<StatusBar.Target />
</header>
);
}
function Page() {
return (
<main style={{ padding: "20px" }}>
<p>This is the main content of the page.</p>
{/* Teleport "Loading..." into the header */}
<StatusBar.Source>
<div style={{ color: "blue", fontWeight: "bold" }}>Loading content...</div>
</StatusBar.Source>
<p>More page content here.</p>
</main>
);
}
function App() {
return (
<div>
<Header />
<Page />
</div>
);
}
const rootElement = document.getElementById("root");
if (rootElement) {
ReactDOM.createRoot(rootElement).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
} else {
console.error("Root element not found");
}