Skip to content

NotSupportedError: Failed to execute 'createElement' on 'Document': The result must not have attributes when using media-chrome React wrappers with Next.js 16 #8

@spuppo-mux

Description

@spuppo-mux

Reproduction example: Open the latest media-chrome NextJS example for React Wrappers
https://media-chrome-demo-nextjs-62k8eebf8-mux.vercel.app/react-wrappers

Opening this example through a link or pressing unmount and mount will log this message.

Uncaught NotSupportedError: Failed to execute 'createElement' on 'Document': The result must not have attributes

Reloading that same page does not trigger the error.

Note

Disclaimer: Info created with Claude

Background

ce-la-react's createComponent has an SSR path that generates <template shadowrootmode="open"> as a light DOM child of each custom element during server rendering:

// ce-la-react/dist/ce-la-react.js
if (typeof window === "undefined" && elementClass?.getTemplateHTML && elementClass?.shadowRootOptions) {
  // adds <template shadowrootmode="open"> as first child
  reactProps.children = [templateShadowRoot, reactProps.children];
}

This worked correctly in Next.js ≤15 because the browser's native HTML parser consumed <template shadowrootmode> as Declarative Shadow DOM before React hydrated — so by the time React walked the DOM, the template was gone and the light DOM matched the client vDOM.


What broke in Next.js 16

Next.js 16 delivers some page content via JavaScript insertion (streaming/RSC payloads) rather than through the initial HTML parse. Content inserted via JS (e.g. innerHTML, insertAdjacentHTML) is not processed as Declarative Shadow DOM — the <template shadowrootmode> stays in the light DOM as a regular element.

This creates a mismatch:

DOM: <media-controller> has <template> as a light child (not consumed)
Client vDOM: no <template> (ce-la-react skips it when typeof window !== "undefined")
React 19 falls back to client-side re-rendering of the mismatched subtree, calling document.createElement('media-controller') etc. programmatically. Per the Custom Elements spec, if a constructor sets any attributes before document.createElement returns, the browser throws NotSupportedError. This kills the render.


Proposed Fix (ce-la-react)

The typeof window === "undefined" guard is the wrong condition to use. The DSD SSR template only helps when HTML is delivered via the native parser. When it's not, it causes breakage.

  • Option A (safest): Remove the DSD SSR template path entirely. All media-chrome elements already guard against this in their constructors with if (!this.shadowRoot) { attachShadow(); ... }, so they degrade gracefully.

  • Option B: Expose a disableDSD or ssr option in createComponent so callers can opt out.


Affected versions

ce-la-react: 0.3.2 (latest)
next: ~16.1.1
react: 19.2.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions