pluggable-react
v0.1.0
Published
Create React components that can be overridden globally or via context
Maintainers
Readme
pluggable-react
Create React components that can be overridden globally or via context. Useful for design systems, white-label apps, and dependency injection of UI.
Installation
npm install pluggable-react reactUsage
1. Create a pluggable component
Use createPluggable to define a component with a default implementation that can be swapped out. The first argument is a unique id used to look up overrides in the registry:
import { createPluggable } from "pluggable-react";
const DefaultButton = ({ label, onClick }: { label: string; onClick?: () => void }) => (
<button type="button" onClick={onClick}>{label}</button>
);
export const Button = createPluggable("MyApp.Button", DefaultButton);
// Button.id === "MyApp.Button"2. Override via context
Wrap your tree with PluggableComponentRegistry and pass a map of component ids to replacement components. Any usage of Button under that provider will render your custom component instead.
Because pluggable components toString() to their id, you can use the component itself as the key:
import { PluggableComponentRegistry } from "pluggable-react";
import { Button } from "./Button";
const CustomButton = (props: any) => (
<button className="custom" {...props}>{props.label}</button>
);
function App() {
return (
<PluggableComponentRegistry components={{ [Button]: CustomButton }}>
<Button label="Click me" />
</PluggableComponentRegistry>
);
}You can also use the id string: components={{ "MyApp.Button": CustomButton }}.
Overrides are merged with any parent registry, so you can override only some components at different levels of the tree.
3. Override globally (imperative)
Pluggable components expose a .replace() method so you can set a single global override without context:
import { Button } from "./Button";
Button.replace((props) => <button className="global-override">{props.label}</button>);
// Later: revert to default
Button.replace(null);Context overrides take precedence over the static override; the static override is used when no context override is provided.
API
| Export | Description |
|--------|-------------|
| createPluggable(id, DefaultComponent) | Returns a pluggable component with .id, .replace(), displayName, and toString() (returns id, so you can use [Button]: CustomButton). |
| PluggableComponentRegistry | Provider that accepts a components map of id → component to override within its subtree. |
| usePluggableComponentFromRegistry(idOrComponent) | Hook that returns the override for the given id string or pluggable component from the nearest registry, or undefined. |
| PluggableComponentRegistryContext | React context used by the registry (for advanced use). |
Requirements
- React 18+
- TypeScript (optional; types are included)
License
MIT
