Slot & Fill component for merging React subtrees together.
Check out the simple demo on glitch (view source)
npm install react-slot-fill --save
git clone https://github.com/camwest/react-slot-fill
cd react-slot-fill
npm start
Note These examples use React Fiber Alpha
import { Slot, Fill } from 'react-slot-fill';
const Toolbar = (props) =>
<div>
<Slot name="Toolbar.Item" />
</div>
export default Toolbar;
Toolbar.Item = (props) =>
<Fill name="Toolbar.Item">
<button>{ props.label }</button>
</Fill>
import Toolbar from './Toolbar';
const Feature = () =>
[
<Toolbar.Item label="My Feature!" />
];
import Toolbar from './Toolbar';
import Feature from './Feature';
import { Provider } from 'react-slot-fill';
const App = () =>
<Provider>
<Toolbar />
<Feature />
</Provider>
ReactDOMFiber.render(
<App />,
document.getElementById('root')
);
Creates a Slot/Fill context. All Slot/Fill components must be descendants of Provider. You may only pass a single descendant to Provider
.
interface Provider {
/**
* Returns instances of Fill react components
*/
getFillsByName(name: string): Fill[];
/**
* Return React elements that were inside Fills
*/
getChildrenByName(name: string): React.ReactChild[];
}
getFillsByName
and getChildrenByName
are really useful for testing Fill components.
See src/lib/__tests/Provider.test.tsx for an example.
Expose a global extension point
import { Slot } from 'react-slot-fill';
interface Props {
/**
* The name of the component. Use a symbol if you want to be 100% sue the Slot
* will only be filled by a component you create
*/
name: string | Symbol;
/**
* Props to be applied to the child Element of every fill which has the same name.
*
* If the value is a function, it must have the following signature:
* (target: Fill, fills: Fill[]) => void;
*
* This allows you to access props on the fill which invoked the function
* by using target.props.something()
*/
fillChildProps?: {[key: string]: any}
/**
* A an optional function which gets all of the current fills for this slot
* Allows sorting, or filtering before rendering. An example use-case could
* be to only show a limited amount of fills.
*
* By default Slot injects an unstyled `<div>` element. If you want greater
* control over presentation use this function.
*
* @example
* <Slot name="My.Slot">
* {(items) => <Component>{items}</Component>}
* </Slot>
*/
children?: (fills) => JSX.Element
}
Render children into a Slot
import { Fill } from 'react-slot-fill';
interface Props {
/**
* The name of the slot that this fill should be related to.
*/
name: string | Symbol
/**
* one or more JSX.Elements which will be rendered
*/
children: JSX.Element | JSX.Element[]
}
You can add additional props to the Fill which can be accessed in the parent node of the slot via fillChildProps.