npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

create-slot

v4.0.0

Published

Render React content in a different place in your component tree. You do not need portals, prop drilling, or shared state. `create-slot` gives you type-safe slots. Any feature in your app can fill a slot, and one or more hosts render the content.

Readme

Create Slot

Render React content in a different place in your component tree. You do not need portals, prop drilling, or shared state. create-slot gives you type-safe slots. Any feature in your app can fill a slot, and one or more hosts render the content.

Documentation — guides, live demos, and a type-checked API reference, plus an FAQ.

For AI agents — install the create-slot skill so your coding agent reads the current docs, or point it straight at the LLM documentation index and the full documentation for LLMs.


Why create-slot?

  • Simple model: features declare what they render. Pages and layouts decide where it appears.
  • Type-safe: host props are typed through generics and useProps().
  • No dependencies: a small API surface.
  • Multiple hosts: one fill renders in every mounted host.
  • Ordering: control the position with the optional order prop.
  • Server rendering: use the plugin registry when the content must be in the HTML.

Installation

npm install create-slot
# or
pnpm add create-slot
# or
yarn add create-slot

Quick start

import * as React from "react"
import { createSlot } from "create-slot"

// 1) Define your slots
const Slots = {
  Menu: createSlot<{ n: number; inc: () => void }>(),
}

// 2) Place a Host where content should render
function Menu() {
  const [n, inc] = React.useReducer((x) => x + 1, 0)

  return (
    <aside>
      <h1>
        Menu <button onClick={inc}>{n}</button>
      </h1>
      <ul>
        <li>Home</li>
        <li>Products</li>
        <Slots.Menu.Host n={n} inc={inc}>
          <li>Placeholder</li>
        </Slots.Menu.Host>
      </ul>
    </aside>
  )
}

// 3) Fill the slot from anywhere
function FeatureA() {
  const [n, inc] = React.useReducer((x) => x + 1, 0)
  return (
    <Slots.Menu order={0}>
      <li>
        Feature A <button onClick={inc}>Inner counter: {n}</button>
      </li>
    </Slots.Menu>
  )
}

function FeatureB() {
  return (
    <Slots.Menu order={1}>
      <li>
        Feature B <HostPropsExample />
      </li>
    </Slots.Menu>
  )
}

function HostPropsExample() {
  const { n, inc } = Slots.Menu.useProps()
  return <button onClick={inc}>Host counter: {n}</button>
}

How it works

  • createSlot<T>() returns a Slot component with two extras: Host and useProps().
  • When a <Slot> renders, it registers a fill. A fill is a React element with an order.
  • Each Host renders the active fills in order. If there are no fills, the host renders its own children.
  • useProps() gives a fill the props of the host that renders it. One fill can adapt to each host.

Use this pattern for a shared menu that many features contribute to, or for a list where each item adapts to its host.


API

function createSlot<T>(): Slot<T>
type Slot<Props> = React.FC<{
  children: React.ReactElement
  order?: number
}> & {
  Host: React.FC<React.PropsWithChildren<Props>>
  useProps(): Props
}
  • <Slot order?> registers a fill. Every mounted Slot.Host renders it. order controls the position.
  • <Slot.Host {...props}>default</Slot.Host> declares where fills render. It also gives typed props to the fills.
  • Slot.useProps() returns the props of the current host. Call it inside a fill.

Behavior:

  • If no fills are mounted, the host renders its own children as the default UI.
  • When a fill unmounts, all hosts remove it.
  • Many hosts of one slot render the same fills. useProps() returns the props of the host that renders the fill.
  • order is a priority, not an array index. Two fills with the same order both render, in registration order.
  • order is read one time, when the fill mounts. A later change does not move the fill.

For more, see the slots guide, ordering, and recipes.


Server rendering: the plugin registry

A fill's server and first hydration snapshots are intentionally empty. It registers from an effect after hydration, so the server sends the children of each host and the fills replace them on the client.

If the content must be in the HTML, use the plugin registry. A contribution is data under a required id; resolvePlugins — a pure, React-free function — turns the plugin list into a Resolution a host renders synchronously, on the server too:

import { definePlugin, defineSlot, resolvePlugins } from "create-slot/core"
import { SlotHost, SlotProvider } from "create-slot"

const NavMenu = defineSlot<{ current: string }>("nav-menu")

const pricing = definePlugin({
  id: "pricing",
  contributes: [
    NavMenu.contribute("nav-item", { order: 10, component: PricingNavItem }),
  ],
})

const resolution = resolvePlugins([pricing], {
  disable: { contributions: [] }, // per-tenant config, typed overrides — see the guide
})

;<SlotProvider resolution={resolution}>
  <ul>
    <SlotHost slot={NavMenu} props={{ current: route }} />
  </ul>
</SlotProvider>

The only SSR requirement: give the resolver the same inputs, in the same order, on the server and on the client. Under React Server Components the manifest itself can be server-legible — create-slot/core is React-free — so a server layout can resolve the graph and pass the whole Resolution across the client boundary (REGISTRY.md, "React Server Components").

The two channels are separate on purpose: the registry is declarative and addressable; createSlot is the runtime channel for content that depends on live tree state.

See the registry guide for the full API, and server rendering for the details.


Comparison

  • Portals move DOM nodes. create-slot composes the UI logically and keeps context local to each host.
  • Context requires you to push arrays of elements through a shared value. With create-slot, fills declare themselves and hosts render them.
  • Global stores must be read and written by your code. The store of create-slot is internal.

Examples

Three versions of one CRM. The SPA uses createSlot only. The two Next.js apps share examples/crm-core and render the same plugin manifest.

npm run dev:spa        # http://localhost:5173 — client-rendered, createSlot only
npm run dev:next-pages # http://localhost:3000 — Next.js pages router, SSR
npm run dev:next-app   # http://localhost:3001 — Next.js app router, RSC + streaming
  • examples/spa — a plugin is a component. To install it, mount it as a child of the shell. Per-row hosts give the same fill different props.
  • examples/nextjs-pages — the registry instead. View the page source to see the contributions in the HTML that the server sends.
  • examples/nextjs-app — the same app with React Server Components: the server layout resolves the graph and hands the Resolution across the boundary; one slow contribution streams in after the rest of the page; one host has no client half at all.

License

MIT