Scoped by Boundary
Keep APIs local to a React subtree instead of leaking everything into a global event bus.
Expose component methods anywhere in the tree without prop drilling, while keeping scope, typing, async registration, and multi-instance support.
React already handles state well. The hard part is imperative coordination:
Another way to frame it:
| Scenario | React's answer |
|---|---|
| Passing data down, one level | props |
| Passing data down, across levels | Context |
| Exposing actions upward, one level | useImperativeHandle |
| Exposing actions upward, across levels | Blank (filled by react-api-bridge) |
react-api-bridge treats these as scoped imperative APIs instead of event broadcasts.
Think of it as:
ref, but not limited to direct parent-child linksContext, but for imperative capabilities instead of plain valuesUse react-api-bridge when your real intent is:
Use an event bus when your real intent is:
import { useState } from 'react';
import {
createBoundary,
createBridge,
useAPI,
useRegister
} from '@ryo-98/react-api-bridge';
interface AppAPIs {
modal: {
open: (content: string) => void;
close: () => void;
};
}
const bridge = createBridge<AppAPIs>();
const Boundary = createBoundary(bridge);
function ModalHost() {
const [content, setContent] = useState<string | null>(null);
useRegister(bridge, 'modal', () => ({
open: setContent,
close: () => setContent(null)
}), []);
if (!content) return null;
return <dialog open>{content}</dialog>;
}
function OpenButton() {
const modalAPI = useAPI(bridge, 'modal');
return (
<button onClick={() => modalAPI.current?.open('Hello from anywhere')}>
Open modal
</button>
);
}
export default function App() {
return (
<Boundary>
<ModalHost />
<OpenButton />
</Boundary>
);
}Continue with the Getting Started guide.