UNPKG

nano-slots

Version:

A super lightweight modern alternative to [`react-slot-fill`](https://github.com/camwest/react-slot-fill) with familiar API.

176 lines (125 loc) 4.14 kB
# nano-slots A super lightweight modern alternative to [`react-slot-fill`](https://github.com/camwest/react-slot-fill) with familiar API. - [x] Control sub-components rendering with `Slot` and `Fill` - [x] Render content of sub-component in multiple places - [x] Speedy - `Fill` and `Slot` communicate directly with each other - [x] Tested with [`testing-library`](https://testing-library.com) - [x] Written in TypeScript - [x] Zero dependencies - [x] Only ~431 B ## 📦 Install ```sh npm i -S nano-slots ``` ```sh yarn add nano-slots ``` ## 💻 Usage ### Create a component and define slots ```js import { Box, Flex } from 'theme-ui' import { SlotsProvider, Slot } from 'nano-slots' export const MediaObject = ({ children }) => ( <SlotsProvider> <Flex> <Box mr={3}> <Slot name="media-side" /> </Box> <Box> <Box mb={2}> <Slot name="media-title" /> </Box> <Box> <Slot name="media-description" /> </Box> {children} </Box> </Flex> </SlotsProvider> ) ``` ### Render elements directly inside each slot ```js import { Fill } from 'nano-slots' import { MediaObject } from './media-object' const MyApp = () => ( <MediaObject> <Fill name="media-side"> <img src='https://placekitten.com/200' alt="Kitten" /> </Fill> <Fill name="media-title"> <h3>Mew</h3> </Fill> <Fill name="media-description"> <p>Purr purr purr</p> </Fill> </MediaObject> ) ``` [![Edit nano-slots](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/nano-slots-s0y0t?fontsize=14&hidenavigation=1&theme=dark) ## 📖 API ### `SlotsProvider` ```js import { SlotsProvider } from 'nano-slots' ``` #### Props - `children: ReactNode` — any valid react children element #### Description Creates a context for `Slot` / `Fill` components. ### `Slot` ```js import { Slot } from 'nano-slots' ``` #### Props - `name: string` — unique slot name for current `SlotsProvider` - `children?: ReactNode` — fallback in case `Fill` with matching `name` not provided, optional - `onChange?(hasFilled: boolean): void` — callback for detecting state changes, on `true` children of matching `Fill` is rendered and fallback is hidden #### Description Define the target slot for `Fill` component. Can be used multiple times with the same name inside each `SlotsProvider`. ### `Fill` ```js import { Fill } from 'nano-slots' ``` #### Props - `name: string` — unique slot name for current `SlotsProvider` - `children: ReactNode` — will be rendered inside matching `Slot` #### Description Render children into matching `Slot` of current `SlotsProvider`. ### `createSlots` ```js import createSlots from 'nano-slots' ``` #### Description Designed for more advanced usages and stronger types. Returns an object containing: - `.Provider` — same as [`SlotsProvider`](#SlotsProvider), but with different context - `.Slot` — same as [`Slot`](#Slot), but with own context - `.Fill` — same as [`Fill`](#Fill), but with own context Returned `Slot` and `Fill` can be used without a `Provider`. ### Types ```ts export interface ProviderProps { children: React.ReactNode; } export function SlotsProvider(props: ProviderProps): JSX.Element; export interface SlotProps<Names extends PropertyKey> { name: Names; children?: React.ReactNode; } export function Slot(props: SlotProps): JSX.Element; export interface FillProps<Names extends PropertyKey> { name: Names; children?: React.ReactNode; } export function Fill(props: FillProps): null; export default function createSlots<Names extends PropertyKey>(): { Provider: (props: SlotsProviderProps): JSX.Element; Slot: (props: SlotProps<Names>): JSX.Element; Fill: (props: FillProps<Names>): null; } ``` ## Alternatives - [`react-slot-fill`](https://github.com/camwest/react-slot-fill) - abandoned project that inspired this one - [`react-view-slot`](https://github.com/robik/react-view-slot) - more modern approach, but [12x times bigger](https://bundlephobia.com/result?p=react-view-slot@1.0.1) --- MIT © John Grishin