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

faux-slots

v0.2.0

Published

Simulate <slot> behavior in light DOM for Preact, Lit, and vanilla web components

Readme

faux-slots

Why should you have to choose between the power of Shadow DOM slotting and the convenience of light DOM rendering and global styling? Well, you shouldn't.

A tiny utility to simulate <slot> behavior in light DOM. Works with Preact (via custom elements), Lit, and vanilla web components. Built for composability, styleability, and performance.

Inspired by Shadow DOM slotting, but built for real-world styling and a11y flexibility.

Get the best of both worlds:

  • Native-feeling slots with named targets and default content
  • Full control over DOM layout
  • Light DOM rendering for predictable cascading styling
  • Greater accessibility support due to nothing being hidden behind the shadow DOM

✨ Features

  • Native-like slot attribute API (default: slot="name")
  • Full control over slot layout and fallback content
  • Works with or without Shadow DOM
  • Preact, Lit, and vanilla web component support
  • SSR-safe, efficient DOM placement, and slotchange events

📦 Installation

npm install faux-slots

Requires preact and/or lit as peer dependencies depending on which integrations you use.


🚀 Usage

Preact custom element

import { registerFauxSlottedElement, JSXSlot } from 'faux-slots'

function MyComponent() {
  return (
    <div>
      <header>
        <JSXSlot name="header" />
      </header>
      <main>
        <JSXSlot />
      </main>
      <footer>
        <JSXSlot name="footer" />
      </footer>
    </div>
  )
}

registerFauxSlottedElement(MyComponent, 'my-element')

Lit element (directive)

import { html } from 'lit'
import { FauxSlotLitElement, fauxSlot } from 'faux-slots'

class MyElement extends FauxSlotLitElement {
  render() {
    return html`
      <header ${fauxSlot('header')}></header>
      <main ${fauxSlot('default')}></main>
      <footer ${fauxSlot('footer')}></footer>
    `
  }
}
customElements.define('my-element', MyElement)

Or with initFauxSlotsLit if you can't extend FauxSlotLitElement:

import { LitElement, html } from 'lit'
import { initFauxSlotsLit } from 'faux-slots'

class MyElement extends LitElement {
  firstUpdated() {
    initFauxSlotsLit(this)
  }
  render() {
    return html`
      <header faux-slot="header"></header>
      <main faux-slot="default"></main>
    `
  }
}
customElements.define('my-element', MyElement)

Vanilla custom element

import { attachAllSlots } from 'faux-slots'

class MyElement extends HTMLElement {
  connectedCallback() {
    this.innerHTML = `
      <header faux-slot="header"></header>
      <main faux-slot="default"></main>
    `
    attachAllSlots(this)
  }
}
customElements.define('my-element', MyElement)

Using the element in HTML

<my-element>
  <h1 slot="header">Hello!</h1>
  <p>This is the default content.</p>
  <span slot="footer">Footer here</span>
</my-element>

🧪 Local Example

pnpm run example:preact

Visit http://localhost:5173.


📚 API

Preact

registerFauxSlottedElement(Component, tag, observedAttrs?, options?)

Registers a Preact functional component as a custom element with faux slot support.

  • Component: Preact functional component
  • tag: Custom element tag name (must contain a -)
  • observedAttrs: Attributes to observe and reflect as props
  • options:
    • slotAttr: Attribute used to identify slotted children (default: "slot")
    • shadow: Use Shadow DOM (default: false)
registerFauxSlottedElement(MyComponent, 'my-el', ['title'], { shadow: false })

useFauxSlotTarget(name?)

Hook that returns a ref callback. Attach to a container element to receive slotted nodes for the given slot name.

const slotRef = useFauxSlotTarget('header')
return <div ref={slotRef} />

useFauxStage(name?)

Like useFauxSlotTarget, but also returns refs to the container and the host element. Returns [ref, stageRef, hostRef].

const [ref, stageRef, hostRef] = useFauxStage('header')
return <div ref={ref} />

JSXSlot

Declarative slot container for use inside Preact components. Renders slotted content into the container, with optional fallback.

<JSXSlot name="footer" fallback={<em>No footer provided</em>} />

Props:

  • name: Slot name (default: "default")
  • fallback: Content to show when the slot is empty
  • as: HTML tag to use as container (default: "div")
  • Any additional HTML attributes are forwarded to the container element

Lit

FauxSlotLitElement

Base class for LitElement. Calls collectSlots before the first render so REGISTRY is populated when directives run. Extend this instead of LitElement when using the fauxSlot directive.

fauxSlot(name?)

Lit element directive. Attach to any element in a Lit template to receive slotted content for the given slot name.

html`<div ${fauxSlot('header')}></div>`

initFauxSlotsLit(host, slotAttr?)

Imperatively wires all [faux-slot] elements inside a Lit element's shadow root. Call from firstUpdated(). Installs a MutationObserver to handle dynamically added slot targets.

  • host: The LitElement instance
  • slotAttr: Attribute used to identify source nodes (default: "slot")

Vanilla

attachAllSlots(host, slotAttr?)

Scans host for elements with [faux-slot] attributes and wires slotted content into them. Installs a MutationObserver to handle dynamically added slot targets. Call from connectedCallback().

  • host: The custom element
  • slotAttr: Attribute used to identify source nodes (default: "slot")

Core engine

hasSlot(host, name?)

Returns true if the named slot has content.

hasSlot(el, 'header') // true or false

getSlottedNodes(host, name?)

Returns the DOM nodes assigned to the named slot.

const nodes = getSlottedNodes(el, 'default')

collectSlots(host, slotAttr?)

Collects and detaches slotted children from host into the internal registry. Idempotent — safe to call multiple times.

attachSlotContent(host, container, slotName?, slotAttr?)

Places the nodes for slotName into container. Dispatches a slotchange event if the DOM changed.

dispatchSlotChange(host, slot)

Dispatches a slotchange CustomEvent on the host element.


Roadmap

  • [x] Default slot fallback
  • [x] slotchange event dispatch
  • [x] Shadow DOM toggle support
  • [x] Custom Element compatibility
  • [x] Lit directive and base class
  • [x] Vanilla web component support
  • [ ] Prop forwarding in JSXSlot

Author

Built with care by Caleb Pierce.