You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
bug: elm.attachShadow is not a function TypeError in Angular SSR app since Ionic v8.2.4 #29751
I have searched for existing issues that already report this problem, without success.
Ionic Framework Version
v8.x
Current Behavior
Since v8.2.4 Ionic components like ion-button and ion-chip produce an elm.attachShadow is not a function TypeError in Angular apps with server side rendering (SSR) enabled.
The TypeError did not occur in version 8.2.2 and prior, but in every version since 8.2.4.
Expected Behavior
No TypeError like in v8.2.2 and prior.
Steps to Reproduce
See the code reproduction URL for a minimal app on GitHub showcasing the error (steps to run the app in the README).
The modules-based Angular app was generated with Angular CLI version 18.1.3 with the command:
ng new ionic-angular-ssr-attachShadow-typeError --ssr=true --standalone=false --style=scss
I then added @ionic/angular and @ionic/angular-server, configured Ionic and switched to Angular’s older browser builder which I’m using in my actual project (and as far as I know Ionic doesn’t work in Angular standalone SSR apps using the new Vite-based application builder). See the commit history in the code reproduction repository for a detailed account of the code changes.
Once you have the code reproduction app running you will get the TypeError in the terminal.
In addition, building the app catches the error also at compile time:
> ng build my-app --watch
TypeError: o.attachShadow is not a function
at Mu (file:///[redacted]/.angular/prerender-root/d62c222d-bf22-49a2-84e2-4076e9839a1f/chunk-RESHKSIQ.mjs:2:26911)
[...]
EDIT: if helpful, here a more detailed stack-trace:
TypeError: elm.attachShadow is not a function
at proxyHostElement ([redacted]\.angular\cache\18.2.9\[redacted]\vite\deps_ssr\@ionic_angular-server.js:1993:15)
at patchElement2 ([redacted]\.angular\cache\18.2.9\[redacted]\vite\deps_ssr\@ionic_angular-server.js:2104:17)
at patchChild2 ([redacted]\.angular\cache\18.2.9\[redacted]\vite\deps_ssr\@ionic_angular-server.js:2110:13)
at patchChild2 ([redacted]\.angular\cache\18.2.9\[redacted]\vite\deps_ssr\@ionic_angular-server.js:2113:15)
at patchChild2 ([redacted]\.angular\cache\18.2.9\[redacted]\vite\deps_ssr\@ionic_angular-server.js:2113:15)
at patchChild2 ([redacted]\.angular\cache\18.2.9\[redacted]\vite\deps_ssr\@ionic_angular-server.js:2113:15)
at patchChild2 ([redacted]\.angular\cache\18.2.9\[redacted]\vite\deps_ssr\@ionic_angular-server.js:2113:15)
at patchChild2 ([redacted]\.angular\cache\18.2.9\[redacted]\vite\deps_ssr\@ionic_angular-server.js:2113:15)
at hydrateApp ([redacted]\.angular\cache\18.2.9\[redacted]\vite\deps_ssr\@ionic_angular-server.js:2144:9)
at hydrateAppClosure ([redacted]\.angular\cache\18.2.9\[redacted]\vite\deps_ssr\@ionic_angular-server.js:30085:5)
Not sure if it's helpful, since the error looks like a compile-time error anyway: my root app component has host: { ngSkipHydration: 'true' }, and the error is reported at run-time inside the hydrateApp() function (that I suppose shouldn't be executed at runtime given the above setting).
Still get the error in Ionic 8.6.0, though slightly different:
TypeError: this.attachShadow is not a function
at ctor.createShadowRoot (C:\Users\xxxxxx\GitHub\ionic-angular-ssr-attachShadow-typeError\dist\app\server\main.js:1:180912)
at proxyHostElement (C:\Users\xxxxxx\GitHub\ionic-angular-ssr-attachShadow-typeError\dist\app\server\main.js:1:241935)
at patchElement2 (C:\Users\xxxxxx\GitHub\ionic-angular-ssr-attachShadow-typeError\dist\app\server\main.js:1:243771)
at patchChild2 (C:\Users\xxxxxx\GitHub\ionic-angular-ssr-attachShadow-typeError\dist\app\server\main.js:1:243843)
at patchChild2 (C:\Users\xxxxxx\GitHub\ionic-angular-ssr-attachShadow-typeError\dist\app\server\main.js:1:243933)
at patchChild2 (C:\Users\xxxxxx\GitHub\ionic-angular-ssr-attachShadow-typeError\dist\app\server\main.js:1:243933)
at patchChild2 (C:\Users\xxxxxx\GitHub\ionic-angular-ssr-attachShadow-typeError\dist\app\server\main.js:1:243933)
at hydrateApp (C:\Users\xxxxxx\GitHub\ionic-angular-ssr-attachShadow-typeError\dist\app\server\main.js:1:246891)
at hydrateAppClosure (C:\Users\xxxxxx\GitHub\ionic-angular-ssr-attachShadow-typeError\dist\app\server\main.js:1:1397098)
at hydrateFactory (C:\Users\xxxxxx\GitHub\ionic-angular-ssr-attachShadow-typeError\dist\app\server\main.js:1:1397205)
v8.2.2 was released a year ago and we have not been able to update since. I hope this does not mean ionic SSR is dead in the future? Does anyone know how to fix the ionic SSR code to work with @stencil/core > 4.20.0 I believe that is the root issue.
We depend on SSR (server side rendering) so we remain
pinned "@ionic/angular": "8.2.2"
and overrides: "@stencil/core": "4.20.0"
I drilled into this with the help of gpt-5.3-codex. You can read what it found below. The primary target for fixing this is in Stencil, because the failing code path is in the Stencil hydrate runtime, but Ionic could also add a guard/workaround in packages/angular-server/src/ionic-server-module.ts. I will open a new issue with Stencil and hope they fix this, since the Ionic team doesn't seem too active about it.
gpt-5.3-codex report on this bug
I investigated this further and can confirm this is a regression introduced after Ionic 8.2.2 when used with Angular SSR (@angular/ssr + @ionic/angular-server).
In newer versions (e.g. 8.7.17), hydration goes through Stencil’s proxyHostElement -> createShadowRoot -> this.attachShadow(...).
On Angular SSR, the server Document is Domino-based, and those elements do not have attachShadow.
Result: SSR crashes with TypeError: this.attachShadow is not a function as soon as an Ionic component is present on the rendered page.
Pinning to 8.2.2 avoids the crash.
Why 8.2.2 works
In the older hydrate path, shadow host setup used SSR-safe fallback behavior instead of directly calling attachShadow on the external server DOM element.
Relevant source location
This appears to come from Stencil hydrate runtime behavior:
Could Ionic add a guard/workaround in packages/angular-server/src/ionic-server-module.ts (or otherwise coordinate with Stencil) so Angular SSR users are not broken on current Ionic 8.x while the Stencil-side hydrate fix is addressed?
I created and shared a minimal repro and got clarification from Stencil that SSR DOM environments without modern custom-element primitives (notably attachShadow) are considered out of scope for hydrateDocument(...) support. So this is not expected to be fixed upstream in Stencil for Domino-like DOMs (including Angular SSR’s current server DOM environment).
In Ionic Angular SSR, this is the place where it applies:
// packages/angular-server/src/ionic-server-module.tsreturnhydrateDocument(doc,{clientHydrateAnnotations: false,// also tested true, see notes belowserializeShadowRoot: 'scoped',excludeComponents: [// ...],});
Result in my repro:
It avoids the server crash (TypeError: this.attachShadow is not a function).
But it is not a complete fix in Angular SSR + Ionic: after client upgrade, rendered output is incorrect (duplicate internals, e.g. extra <button> outside the shadow root for ion-button).
I also tested clientHydrateAnnotations: true; this did not resolve the client mismatch in this repro.
So the current state is:
declarative-shadow-dom path crashes on server with Angular SSR DOM.
scoped avoids crash but causes client/render correctness issues.
Given Stencil’s scope clarification, this now looks like an Ionic Angular SSR integration issue in @ionic/angular-server (how hydrateDocument is invoked and how SSR DOM compatibility is handled).
Could maintainers please triage this and suggest/implement a supported integration path for Angular SSR?
and fixes the earlier duplicate-internals symptom (no extra light-DOM <button> after upgrade)
However, there is still a client hydration error from Angular: TypeError: Cannot read properties of undefined (reading 'hasAttribute')
(stack points into Angular hydration internals / ngSkipHydration checks)
Important confirmation:
if I remove provideClientHydration() from the Angular app, this error disappears.
So there appear to be two separate Angular+Ionic SSR integration issues:
server-side DSD incompatibility with current Angular SSR DOM (attachShadow missing)
client-side Angular hydration mismatch after Ionic SSR processing (even when scoped+annotations is used)
Given Stencil’s scope clarification, this still looks like an Ionic Angular SSR integration problem in @ionic/angular-server (option defaults and hydration compatibility with Angular SSR/client hydration).
The Angular client error (TypeError: Cannot read properties of undefined (reading 'hasAttribute')) appears to be caused by a Stencil non-shadow patching bug affecting .children/.childNodes (notably with ion-app), which was fixed in Stencil 4.40.0. Ionic 8.7.17 ships Stencil 4.38.0.
This suggests a concrete Ionic fix path:
In @ionic/angular-server, use serializeShadowRoot: 'scoped', and
Set clientHydrateAnnotations: true.
Upgrade Ionic’s bundled Stencil runtime to >= 4.40.0.
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.
Activity
crufter commentedon Oct 2, 2024
This is affecting us as well - SSR cannot render the site.
AndrusGerman commentedon Oct 11, 2024
Same problem
kafumanto commentedon Oct 24, 2024
Same problem here.
In addition, building the app catches the error also at compile time:
EDIT: if helpful, here a more detailed stack-trace:
Not sure if it's helpful, since the error looks like a compile-time error anyway: my root app component has
host: { ngSkipHydration: 'true' }, and the error is reported at run-time inside thehydrateApp()function (that I suppose shouldn't be executed at runtime given the above setting).Watchwolf commentedon Nov 25, 2024
Same problem for me with the latest ionic version.
davidquintard commentedon Dec 5, 2024
same problem
davidquintard commentedon Mar 1, 2025
no workaround ?
SebastianKohler commentedon Mar 5, 2025
My guess is that this originates from Stencil, and apparently the Ionic team is working on improving the Stencil SSR performance: https://ionic.io/blog/coming-soon-new-updates-features-for-ionics-open-source-projects
Let's hope the current Stencil work will fix this ...
kafumanto commentedon Mar 5, 2025
I suspect that no one at Ionic has been looking into bug reports for a long time...
crufter commentedon Mar 5, 2025
Probably not applicable to most but in my case the project is a website so I solved this by removing ionic and moving to angular material...
davidquintard commentedon Mar 5, 2025
For my part, i downgraded to ionic 8.2.2.
It works fine.
Watchwolf commentedon Mar 5, 2025
I solved this by removing ssr. I have written a script to generate static page and redirect the search engine to them.
SebastianKohler commentedon Mar 5, 2025
I also pinned version 8.2.2, which is fine for now. Thinking about moving to Angular Material, but it's so much work in the case of my project.
SebastianKohler commentedon Jun 6, 2025
Still get the error in Ionic 8.6.0, though slightly different:
DavidBowdoin commentedon Jul 2, 2025
v8.2.2 was released a year ago and we have not been able to update since. I hope this does not mean ionic SSR is dead in the future? Does anyone know how to fix the ionic SSR code to work with @stencil/core > 4.20.0 I believe that is the root issue.
We depend on SSR (server side rendering) so we remain
pinned "@ionic/angular": "8.2.2"
and overrides: "@stencil/core": "4.20.0"
SebastianKohler commentedon Feb 20, 2026
I drilled into this with the help of
gpt-5.3-codex. You can read what it found below. The primary target for fixing this is in Stencil, because the failing code path is in the Stencil hydrate runtime, but Ionic could also add a guard/workaround inpackages/angular-server/src/ionic-server-module.ts. I will open a new issue with Stencil and hope they fix this, since the Ionic team doesn't seem too active about it.gpt-5.3-codexreport on this bugI investigated this further and can confirm this is a regression introduced after Ionic
8.2.2when used with Angular SSR (@angular/ssr+@ionic/angular-server).What I found
@ionic/angular-servercallshydrateDocument(doc, ...)from@ionic/core/hydrate.8.7.17), hydration goes through Stencil’sproxyHostElement->createShadowRoot->this.attachShadow(...).Documentis Domino-based, and those elements do not haveattachShadow.TypeError: this.attachShadow is not a functionas soon as an Ionic component is present on the rendered page.8.2.2avoids the crash.Why 8.2.2 works
In the older hydrate path, shadow host setup used SSR-safe fallback behavior instead of directly calling
attachShadowon the external server DOM element.Relevant source location
This appears to come from Stencil hydrate runtime behavior:
src/hydrate/platform/proxy-host-element.ts(callscreateShadowRoot)src/utils/shadow-root.ts(createShadowRootcallsattachShadow)Example file:
https://github.com/stenciljs/core/blob/4d322a75878cc14604c7b2cd747cdc3c17249fa5/src/hydrate/platform/proxy-host-element.ts
Request
Could Ionic add a guard/workaround in
packages/angular-server/src/ionic-server-module.ts(or otherwise coordinate with Stencil) so Angular SSR users are not broken on current Ionic 8.x while the Stencil-side hydrate fix is addressed?SebastianKohler commentedon Feb 20, 2026
Quick update after discussing this with Stencil:
I created and shared a minimal repro and got clarification from Stencil that SSR DOM environments without modern custom-element primitives (notably
attachShadow) are considered out of scope forhydrateDocument(...)support. So this is not expected to be fixed upstream in Stencil for Domino-like DOMs (including Angular SSR’s current server DOM environment).Following Stencil’s suggestion (thanks @johnjenkins), I tested an Ionic-side mitigation using
serializeShadowRoot: 'scoped': https://stenciljs.com/docs/hydrate-app#serializeshadowrootIn Ionic Angular SSR, this is the place where it applies:
Result in my repro:
TypeError: this.attachShadow is not a function).<button>outside the shadow root forion-button).clientHydrateAnnotations: true; this did not resolve the client mismatch in this repro.So the current state is:
declarative-shadow-dompath crashes on server with Angular SSR DOM.scopedavoids crash but causes client/render correctness issues.Given Stencil’s scope clarification, this now looks like an Ionic Angular SSR integration issue in
@ionic/angular-server(howhydrateDocumentis invoked and how SSR DOM compatibility is handled).Could maintainers please triage this and suggest/implement a supported integration path for Angular SSR?
SebastianKohler commentedon Feb 23, 2026
Correction/update to my previous comment (I reran everything from clean state and found my earlier conclusion on scoped+annotations was incomplete).
What I can now reproduce reliably:
serializeShadowRootdefault / DSD):TypeError: this.attachShadow is not a function<button>after upgrade)However, there is still a client hydration error from Angular:
TypeError: Cannot read properties of undefined (reading 'hasAttribute')(stack points into Angular hydration internals /
ngSkipHydrationchecks)Important confirmation:
provideClientHydration()from the Angular app, this error disappears.So there appear to be two separate Angular+Ionic SSR integration issues:
attachShadowmissing)Given Stencil’s scope clarification, this still looks like an Ionic Angular SSR integration problem in
@ionic/angular-server(option defaults and hydration compatibility with Angular SSR/client hydration).I pushed a branch with a minimal diagnostic patch (
IonicServerScopedModule) showing the scoped+annotations behavior and remaining Angular hydration error: SebastianKohler/ionic-angular-ssr-attachShadow-typeError@a11b419SebastianKohler commentedon Feb 23, 2026
Follow-up with new findings from Stencil investigation:
The Angular client error (
TypeError: Cannot read properties of undefined (reading 'hasAttribute')) appears to be caused by a Stencil non-shadow patching bug affecting.children/.childNodes(notably withion-app), which was fixed in Stencil4.40.0. Ionic8.7.17ships Stencil4.38.0.This suggests a concrete Ionic fix path:
@ionic/angular-server, useserializeShadowRoot: 'scoped', andclientHydrateAnnotations: true.>= 4.40.0.fix(angular-server): fallback to scoped+annotations when SSR DOM lack…
SebastianKohler commentedon Aug 24, 2026
Completed in #30967.
ionitron-bot commentedon Sep 23, 2026
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.