Built on top of the @radix-ui/react-slot library.
react-bypass is a simple utility React component that can be used as a composable approach to skip its first children and prevent it from rendering. Note that react-bypass is meant to be an escape hatch and other approaches may be considered first. Its main use case is to be able to transform external JSX you may not have control of, received as children.
<Bypass>
<div>
<span>Hello world</span>
</div>
</Bypass>renders
<span>Hello world</span>That is, <div> gets "bypassed".
It is especially useful in cases where you want to conditionally change a button's behavior in a composable way.
import * as React from "react";
import { Dialog, DialogTrigger, DialogContent } from "@radix-ui/react-dialog";
import { Bypass } from "react-bypass";
const ProtectedAction = ({ children }: React.PropsWithChildren) => {
const { isLoggedIn } = useSession();
// Allow regular action when user is logged in
if (isLoggedIn) {
return children;
}
// Bypass the button and replace it with a dialog trigger instead
return (
<Dialog>
<DialogTrigger>
<Bypass>{children}</Bypass>
</DialogTrigger>
<DialogContent>
<SignUp />
</DialogContent>
</Dialog>
);
};// Only allows uploads to start when user is logged in
// When not logged in, the dialog will replace it instead and `startUpload` won't be called
<ProtectedAction>
<button onClick={startUpload}>
<span>Click to upload files</span>
</button>
</ProtectedAction>
// ^ Renders <DialogTrigger><span>...</span></DialogTrigger> if `isLoggedIn = false`To start using the library, install it to your project:
npm i react-bypasspnpm add react-bypassimport { Bypass } from "react-bypass";
// ...
function Title() {
return (
<Bypass>
<div>
<h1>My Awesome Title</h1>
</div>
</Bypass>
);
}
/**
* Output:
*
* <h1>My Awesome Title</h1>
**/The <Bypass> component itself doesn't render anything. Any prop passed onto it will be forwarded down to its children.
Set disabled={true} to disable its default behavior.
react-bypass can be handy in several compositional scenarios:
- Unwrapping third‑party JSX: Drop an outer wrapper from content you do not control (e.g., CMS/MDX-rendered blocks) while preserving the inner structure.
- Integrating with headless/primitive libraries: Replace an outer element to turn a child into a trigger/label without changing the child's code.
- Improving semantics/accessibility: Remove layout-only wrappers to promote the semantically meaningful child to be the rendered element.
- Polymorphic composition: Collapse extra wrappers when composing polymorphic components so the visual/DOM tree stays lean.
- Routing/analytics bridges: Swap an outer button/link wrapper to integrate with a router or analytics collector, keeping the original child intact.
Created in 2024, released under the MIT license.
- Do not rely on
react-bypass(or any UI-only mechanism) as the sole means of protecting actions. Authorization must be enforced at the server and data-access layers. - In Next.js, components that cross the server–client boundary are often wrapped by a
Suspenseboundary implicitly. Usingreact-bypasson such components may end up bypassing theSuspensewrapper rather than the intended child. - If you must operate near a boundary, target a stable, known child element rather than a top-level node that Next.js might wrap.