Skip to content

A super lightweight slots implementation for React

License

Notifications You must be signed in to change notification settings

exah/nano-slots

Repository files navigation

nano-slots

A super lightweight modern alternative to react-slot-fill with familiar API.

  • Control sub-components rendering with Slot and Fill
  • Render content of sub-component in multiple places
  • Speedy - Fill and Slot communicate directly with each other
  • Tested with testing-library
  • Written in TypeScript
  • Zero dependencies
  • Only ~431 B

πŸ“¦ Install

npm i -S nano-slots
yarn add nano-slots

πŸ’» Usage

Create a component and define slots

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

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

πŸ“– API

SlotsProvider

import { SlotsProvider } from 'nano-slots'

Props

  • children: ReactNode β€” any valid react children element

Description

Creates a context for Slot / Fill components.

Slot

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

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

import createSlots from 'nano-slots'

Description

Designed for more advanced usages and stronger types. Returns an object containing:

  • .Provider β€” same as SlotsProvider, but with different context
  • .Slot β€” same as Slot, but with own context
  • .Fill β€” same as Fill, but with own context

Returned Slot and Fill can be used without a Provider.

Types

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


MIT Β© John Grishin