JavaScript Document customElementRegistry Property

Beginner
⏱️ 12 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
Limited availability
Instance property

What You’ll Learn

Document.customElementRegistry is a read-only instance property that returns the CustomElementRegistry for this document, or null. Learn how it relates to window.customElements, why some created documents have a null registry, how ShadowRoot shares the same property name, and five examples with try-it labs.

01

Kind

Read-only

02

Returns

Registry | null

03

Alias

window.customElements

04

Also on

ShadowRoot

05

Support

Limited

06

Status

Not Baseline

Introduction

Custom elements let you invent HTML tags like <my-card>. The browser keeps a registry of those tag names and their class definitions. Most tutorials use window.customElements (or just customElements) to call define(), get(), and whenDefined().

document.customElementRegistry is the Document’s way to reach that registry object. MDN: for documents associated with a Window (a normal page), it is the same global registry as window.customElements. Documents created with createHTMLDocument() often have null by default.

💡
Limited availability

MDN marks this property Limited availability (not Baseline). Always feature-detect ("customElementRegistry" in Document.prototype or a try/catch around reading it). Everyday custom elements via customElements.define() remain widely available.

Related Document tutorials: currentScript, cookie, Document constructor.

Understanding Document.customElementRegistry

A read-only instance property on Document. Value is a CustomElementRegistry or null.

  • Main page document — usually equals window.customElements (MDN).
  • Programmatic documentscreateHTMLDocument() defaults to null (MDN).
  • ShadowRoot — same property name for scoped registries (MDN).
  • Use the registrydefine(), get(), whenDefined(), getName() (where supported).
  • Not assignable — you read the registry; you do not assign a new one via this property.

📝 Syntax

JavaScript
document.customElementRegistry

Value

A CustomElementRegistry object, or null.

Safe read (feature-detect)

JavaScript
const registry =
  "customElementRegistry" in document
    ? document.customElementRegistry
    : (window.customElements || null);

console.log(registry);

⚡ Quick Reference

GoalCode / note
Read document registrydocument.customElementRegistry
Same as global?document.customElementRegistry === window.customElements
Programmatic docOften null after createHTMLDocument()
Define a tagregistry.define("my-x", class extends HTMLElement {})
FallbackUse window.customElements when property missing
MDN statusLimited availability (not Baseline)

🔍 At a Glance

Four facts about document.customElementRegistry.

Type
CustomElementRegistry | null

Or null

Access
read-only

No setter

Main page
=== customElements

Usually

Status
limited

Not Baseline

📋 Common CustomElementRegistry methods

MethodPurpose
define(name, constructor)Register a custom element class
get(name)Return the constructor, or undefined
whenDefined(name)Promise that resolves when the name is defined
upgrade(root)Upgrade custom elements in a subtree
getName(constructor)Look up the registered name (where supported)

Examples Gallery

Examples follow MDN Document: customElementRegistry. Feature-detect in unsupported browsers. Use View Output or Try It Yourself for each case.

📚 Getting Started

Compare the main document registry with the global one (MDN).

Example 1 — Same as window.customElements (MDN)

On a Window-associated page document, both accessors refer to the same registry.

JavaScript
// Main document registry is the global one (when supported):
console.log(
  document.customElementRegistry === window.customElements
); // true on Window-associated documents
Try It Yourself

How It Works

MDN: the main document shares the global CustomElementRegistry also exposed as window.customElements.

Example 2 — createHTMLDocument() Has null (MDN)

Programmatically created documents often have no registry by default.

JavaScript
const newDoc = document.implementation.createHTMLDocument("New document");
console.log(newDoc.customElementRegistry); // null (MDN)
Try It Yourself

How It Works

Do not assume every Document instance has a registry—check for null before calling define().

📈 Detect, Define & ShadowRoot

Safe detection, a tiny custom element, and the ShadowRoot twin property.

Example 3 — Feature-Detect the Property

Fall back to window.customElements when the Document property is missing.

JavaScript
const hasDocProp = "customElementRegistry" in document;
const registry = hasDocProp
  ? document.customElementRegistry
  : window.customElements;

console.log("Document property present:", hasDocProp);
console.log("Using registry:", !!registry);
Try It Yourself

How It Works

Limited availability means some browsers expose only window.customElements. Detect before relying on the Document property.

Example 4 — Define via the Document Registry

Use the resolved registry to register a simple autonomous custom element.

JavaScript
const registry =
  document.customElementRegistry || window.customElements;

if (registry && !registry.get("hello-chip")) {
  registry.define(
    "hello-chip",
    class extends HTMLElement {
      connectedCallback() {
        this.textContent = this.textContent || "Hello custom element!";
      }
    }
  );
}

document.body.appendChild(document.createElement("hello-chip"));
Try It Yourself

How It Works

get() avoids double-define errors if the lab runs more than once. Prefer unique names in real apps.

Example 5 — ShadowRoot.customElementRegistry (MDN)

The same property name exists on shadow roots for scoped registries.

JavaScript
const host = document.createElement("div");
const root = host.attachShadow({ mode: "open" });

console.log(
  "ShadowRoot has customElementRegistry:",
  "customElementRegistry" in root
);
console.log("shadow registry:", root.customElementRegistry);
// May be null or a scoped/global registry depending on browser & options
Try It Yourself

How It Works

Scoped custom element registries associate definitions with a shadow tree instead of the whole page—advanced, still rolling out.

🚀 Common Use Cases

  • Read the document registry explicitly — when APIs take a CustomElementRegistry object.
  • Null checks — before defining elements on programmatically created documents.
  • Scoped registries — micro-frontends / component libraries isolating tag names (advanced).
  • ShadowRoot association — inspect which registry a shadow tree uses.
  • Teaching / debugging — prove main document === window.customElements.
  • Prefer customElements for basics — wider support for everyday define().

🧠 How the Document Registry Fits In

1

Page loads in a Window

Browser creates a global CustomElementRegistry.

Window
2

Exposed two ways

window.customElements and (where supported) document.customElementRegistry.

Accessors
3

You call define / get

Tag names map to classes; upgraded elements appear in the DOM.

Define
4

Other documents may differ

createHTMLDocument() can return null; ShadowRoot may use a scoped registry.

📝 Notes

  • MDN: Limited availability (not Baseline) — no Deprecated / Experimental / Non-standard banner on MDN for this page.
  • Read-only; value is CustomElementRegistry or null.
  • Main Window documents: same object as window.customElements (MDN).
  • Also available on ShadowRoot under the same name (MDN).
  • Feature-detect; fall back to window.customElements for basic custom elements.
  • Related: currentScript, cookie, Document constructor.

Limited Browser Support

Document.customElementRegistry is marked Limited availability on MDN (not Baseline). Everyday window.customElements has much wider support. Logos use the shared browser-image-sprite.png sprite from this project.

Limited availability · Not Baseline

Document.customElementRegistry

CustomElementRegistry or null — the registry associated with this document (often the same as window.customElements).

Limited Not Baseline
Google Chrome Supporting recent Chromium — verify version
Check version
Microsoft Edge Follow Chromium support
Check version
Opera Follow Chromium where available
Check version
Mozilla Firefox May require pref / lag behind — feature-detect
Limited
Apple Safari Check current Safari — feature-detect
Limited
Internet Explorer No Custom Elements / no this property
No support
Document.customElementRegistry Limited

Bottom line: Feature-detect document.customElementRegistry. For basic custom elements, window.customElements.define() remains the portable choice. Check current MDN compatibility tables before shipping scoped-registry code.

Conclusion

Document.customElementRegistry exposes the custom element registry for a document (or null). On normal pages it matches window.customElements; on some created documents it does not. Because support is limited, detect the property and keep customElements.define() as your everyday tool.

Continue with defaultView, currentScript, cookie, or the JavaScript hub.

💡 Best Practices

✅ Do

  • Feature-detect before reading document.customElementRegistry
  • Treat null as a real possibility on created documents
  • Use window.customElements for portable beginner examples
  • Check registry.get(name) before re-defining
  • Read MDN compatibility when using scoped registries

❌ Don’t

  • Assume every browser exposes the Document property yet
  • Call methods on a null registry
  • Confuse this Limited property with Baseline customElements
  • Assign to document.customElementRegistry
  • Skip unique tag names (must include a hyphen)

Key Takeaways

Knowledge Unlocked

Five things to remember about document.customElementRegistry

Registry or null — often the same as window.customElements.

5
Core concepts
02

Main page

=== customElements

MDN
🔒03

Access

read-only

DOM
⚠️04

Support

limited

Not Baseline
🎨05

Also on

ShadowRoot

Scoped

❓ Frequently Asked Questions

The CustomElementRegistry associated with this document, or null if one has not been set. On a normal page document it is usually the same object as window.customElements.
MDN does not mark Document.customElementRegistry as Deprecated, Experimental, or Non-standard. It is Limited availability (not Baseline) — support is incomplete across major browsers, so feature-detect before production use.
For documents associated with a Window (the main page), MDN says they are the same global registry. document.customElementRegistry is the Document-side accessor and can be null on some programmatically created documents.
MDN: documents created programmatically (for example via DOMImplementation.createHTMLDocument()) have a null custom element registry by default.
Yes. MDN notes the same customElementRegistry property is also available on ShadowRoot, which matters for scoped custom element registries.
Yes. Defining custom elements with customElements.define() remains the everyday API. Use document.customElementRegistry when you need the document's registry object or to handle null / scoped cases.
Did you know?

Scoped custom element registries exist so two libraries can both define <my-button> without colliding globally—each shadow tree can use its own registry. document.customElementRegistry is part of that newer story, which is why support is still catching up.

Next: defaultView

Learn how to get the Window object associated with a Document.

defaultView →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

6 people found this page helpful