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

@litsx/light-dom-registry

v0.2.1

Published

Contextual light DOM registry runtime for LitSX element delegation

Readme

@litsx/light-dom-registry

npm Release Module Provenance

Runtime support for contextual element resolution in LitSX static lightDom = true components.

Attribution

src/index.js includes code adapted from The Polymer Project's custom elements work. The original BSD-style attribution notice is preserved in the source file and in this package's NOTICE.

What It Does

@litsx/light-dom-registry lets static lightDom = true components keep clean base tags while still using different implementations for the same tag name in different light DOM subtrees.

It does that by:

  • registering one global stand-in proxy per tag on window.customElements
  • attaching a contextual registry to each static lightDom = true host
  • resolving the nearest host registry when a proxy instance is created or connected
  • upgrading the real element in place, without adding a visible wrapper child

This is runtime infrastructure. The transform and LitSX runtime are still responsible for:

  • emitting static elements
  • choosing LightDomElementsMixin
  • calling connectLightDomRegistry(...)

Where The Global Proxy Is Registered

The global proxy registration happens when a light DOM registry defines a tag for the first time:

if (!standInClass) {
  standInClass = createStandInElement(tagName);
  standInClass[STAND_IN_MARK] = true;
  nativeDefine(tagName, standInClass);
}

That path lives in ShimmedCustomElementsRegistry#define(...).

There is also an explicit helper:

ensureLightDomProxy("profile-chip");

which uses the same nativeDefine(...) path when the global stand-in does not exist yet.

Coexistence Demo

Two different light DOM hosts can use the same tag base and still resolve different constructors.

Authored Components

import { LitElement } from "lit";

export function AdminScreen() {
  static lightDom = true;
  return <profile-chip />;
}

AdminScreen.elements = {
  "profile-chip": AdminProfileChip,
};

export function GuestScreen() {
  static lightDom = true;
  return <profile-chip />;
}

GuestScreen.elements = {
  "profile-chip": GuestProfileChip,
};

Lowered Shape

class AdminScreen extends LightDomElementsMixin(LitElement) {
  static elements = {
    "profile-chip": AdminProfileChip,
  };

  createRenderRoot() {
    return this;
  }

  render() {
    return <profile-chip />;
  }
}

class GuestScreen extends LightDomElementsMixin(LitElement) {
  static elements = {
    "profile-chip": GuestProfileChip,
  };

  createRenderRoot() {
    return this;
  }

  render() {
    return <profile-chip />;
  }
}

Runtime Result

When both hosts are mounted in the same document:

<admin-screen>
  <profile-chip></profile-chip>
</admin-screen>

<guest-screen>
  <profile-chip></profile-chip>
</guest-screen>

the two profile-chip nodes share the same globally registered proxy class, but each one upgrades against the nearest host registry:

  • under admin-screen, profile-chip upgrades to AdminProfileChip
  • under guest-screen, profile-chip upgrades to GuestProfileChip

No suffix is added to the tag name, and no extra wrapper node is inserted.

Nested Host Demo

Nearest-host resolution also works when one light DOM host is nested inside another.

<outer-screen>
  <profile-chip></profile-chip>
  <inner-screen>
    <profile-chip></profile-chip>
  </inner-screen>
</outer-screen>

If:

  • OuterScreen.elements["profile-chip"] = OuterProfileChip
  • InnerScreen.elements["profile-chip"] = InnerProfileChip

then:

  • the outer profile-chip upgrades to OuterProfileChip
  • the inner profile-chip upgrades to InnerProfileChip

The closest host context wins.

Collision Rule

If the base tag is already registered globally to a constructor that does not belong to this runtime, the registry throws instead of falling back to a suffixed tag.

That is deliberate. static lightDom = true is preserving the authored tag, not generating an alternative global name.