<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Zahid Hossain</title>
    <description>The latest articles on DEV Community by Zahid Hossain (@zahid_hossain_f95d8baa135).</description>
    <link>https://dev.to/zahid_hossain_f95d8baa135</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4094070%2Ffc625707-7be8-4246-83b0-02a5232bcd9d.jpg</url>
      <title>DEV Community: Zahid Hossain</title>
      <link>https://dev.to/zahid_hossain_f95d8baa135</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zahid_hossain_f95d8baa135"/>
    <language>en</language>
    <item>
      <title>Running Angular 22 With CDK / Material 16: Bridging the `ComponentFactoryResolver` Gap</title>
      <dc:creator>Zahid Hossain</dc:creator>
      <pubDate>Tue, 25 Aug 2026 13:15:19 +0000</pubDate>
      <link>https://dev.to/zahid_hossain_f95d8baa135/running-angular-22-with-cdk-material-16-bridging-the-componentfactoryresolver-gap-1l7k</link>
      <guid>https://dev.to/zahid_hossain_f95d8baa135/running-angular-22-with-cdk-material-16-bridging-the-componentfactoryresolver-gap-1l7k</guid>
      <description>&lt;p&gt;&lt;strong&gt;Subtitle:&lt;/strong&gt; How to keep an older Angular CDK / Material stack alive after Angular 22 removes factory-based component creation — without rewriting your entire UI layer overnight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;code&gt;Angular&lt;/code&gt; · &lt;code&gt;Angular 22&lt;/code&gt; · &lt;code&gt;CDK&lt;/code&gt; · &lt;code&gt;Material&lt;/code&gt; · &lt;code&gt;Migration&lt;/code&gt; · &lt;code&gt;postinstall&lt;/code&gt; · &lt;code&gt;Compatibility Shim&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audience:&lt;/strong&gt; Frontend engineers upgrading Angular core while temporarily pinning &lt;code&gt;@angular/cdk&lt;/code&gt; / &lt;code&gt;@angular/material&lt;/code&gt; to an older major.&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The problem in one sentence&lt;/li&gt;
&lt;li&gt;Why this combination is common&lt;/li&gt;
&lt;li&gt;What Angular 22 actually removed&lt;/li&gt;
&lt;li&gt;How the crash shows up&lt;/li&gt;
&lt;li&gt;Architecture of the fix&lt;/li&gt;
&lt;li&gt;Step-by-step implementation guide&lt;/li&gt;
&lt;li&gt;What each patch does (deep dive)&lt;/li&gt;
&lt;li&gt;How the runtime flow works (visual)&lt;/li&gt;
&lt;li&gt;Pros and cons&lt;/li&gt;
&lt;li&gt;Best practices when you force this compatibility&lt;/li&gt;
&lt;li&gt;Corner cases you must keep in mind&lt;/li&gt;
&lt;li&gt;Exit strategy: how to leave the shim behind&lt;/li&gt;
&lt;li&gt;Checklist before you ship&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. The problem in one sentence
&lt;/h2&gt;

&lt;p&gt;You upgraded &lt;strong&gt;Angular core to 22&lt;/strong&gt;, but you still need &lt;strong&gt;CDK / Material 16&lt;/strong&gt;. The app builds (or almost builds), then dies at runtime when Overlay, Dialog, Menu, SnackBar, or Tabs try to inject APIs that &lt;strong&gt;no longer exist&lt;/strong&gt; in &lt;code&gt;@angular/core@22&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That mismatch is not a bug in your feature code. It is a &lt;strong&gt;version skew&lt;/strong&gt; between framework internals and an older UI toolkit that still speaks the pre-Ivy factory language.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Why this combination is common
&lt;/h2&gt;

&lt;p&gt;Teams often need to split a migration into two tracks:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Track&lt;/th&gt;
&lt;th&gt;Goal&lt;/th&gt;
&lt;th&gt;Risk if delayed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core / build / TypeScript&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stay on a supported Angular major, Node, and TS&lt;/td&gt;
&lt;td&gt;Security, ecosystem lag, CI failures&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CDK / Material / UI rewrite&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Move off legacy Material APIs, theming, and breaking CSS&lt;/td&gt;
&lt;td&gt;Large visual + a11y + regression surface&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Material major upgrades are rarely “bump the package and ship.” They touch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Legacy Material modules (&lt;code&gt;MatLegacy*&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Theme / typography / density&lt;/li&gt;
&lt;li&gt;Overlay-heavy flows (dialogs, menus, snackbars, bottom sheets)&lt;/li&gt;
&lt;li&gt;Custom CDK portals and tooltips&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So a deliberate temporary state looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@angular/core            → 22.x
@angular/cdk             → 16.x   (pinned)
@angular/material        → 16.x   (pinned)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Peer dependency warnings are expected. Runtime breakage is the real blocker.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; This article describes a &lt;strong&gt;temporary compatibility bridge&lt;/strong&gt;, not a long-term architecture. Treat the shim as debt with an owner and a removal date.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3. What Angular 22 actually removed
&lt;/h2&gt;

&lt;p&gt;Angular has been steering away from factory-based dynamic components since Ivy. In Angular 22, the cleanup became a hard break:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ComponentFactoryResolver&lt;/code&gt; — &lt;strong&gt;removed&lt;/strong&gt; from the public API&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ComponentFactory&lt;/code&gt; — &lt;strong&gt;removed&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The old &lt;code&gt;ViewContainerRef.createComponent(factory, index, …)&lt;/code&gt; overload — &lt;strong&gt;gone&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Official direction (paraphrased from Angular’s breaking-change notes):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pass the &lt;strong&gt;component class&lt;/strong&gt; directly to &lt;code&gt;ViewContainerRef.createComponent&lt;/code&gt;, or use the standalone &lt;code&gt;createComponent()&lt;/code&gt; function.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Old pattern (CDK 16 still uses this)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resolver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;componentFactoryResolver&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;resolver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolveComponentFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;viewContainerRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;projectableNodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  New pattern (Angular 22+)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;viewContainerRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;projectableNodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, when there is no &lt;code&gt;ViewContainerRef&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;createComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;environmentInjector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;appRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;elementInjector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customInjector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;projectableNodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CDK / Material 16’s portal and overlay stack still follows the &lt;strong&gt;old&lt;/strong&gt; path. Angular 22 follows only the &lt;strong&gt;new&lt;/strong&gt; path. Something has to translate between them.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. How the crash shows up
&lt;/h2&gt;

&lt;p&gt;Typical symptoms after a “core-only” upgrade:&lt;/p&gt;

&lt;h3&gt;
  
  
  Symptom A — DI token is undefined
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TypeError: Cannot read properties of undefined (reading 'hasOwnProperty')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Overlay / portal code still declares an injection dependency on &lt;code&gt;ComponentFactoryResolver&lt;/code&gt;. In Angular 22 that token is missing, so DI effectively injects &lt;code&gt;undefined&lt;/code&gt;, then blows up inside the injector.&lt;/p&gt;

&lt;h3&gt;
  
  
  Symptom B — Dialog / Menu / Tooltip attach fails later
&lt;/h3&gt;

&lt;p&gt;Even if you somehow get past bootstrap, attaching a component through &lt;code&gt;DomPortalOutlet&lt;/code&gt; or &lt;code&gt;CdkPortalOutlet&lt;/code&gt; can fail because &lt;code&gt;createComponent&lt;/code&gt; is called with a &lt;strong&gt;factory&lt;/strong&gt;, not a &lt;strong&gt;Type&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Symptom C — SnackBar content is empty or throws
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;MatSnackBar&lt;/code&gt; often goes through &lt;code&gt;CdkPortalOutlet&lt;/code&gt;. That path is easy to miss if you only patched &lt;code&gt;DomPortalOutlet&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Symptom D — “It works until I restart / reinstall”
&lt;/h3&gt;

&lt;p&gt;If you hand-edit &lt;code&gt;node_modules&lt;/code&gt; without a &lt;code&gt;postinstall&lt;/code&gt; script, the next clean install wipes the fix. Always automate the patch.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Architecture of the fix
&lt;/h2&gt;

&lt;p&gt;The workable temporary approach has three layers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhmp2flylnipwtfg0ritm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhmp2flylnipwtfg0ritm.png" alt=" " width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Mental model
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Shim in core&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Makes the &lt;strong&gt;token&lt;/strong&gt; exist again for dependency injection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Portal patches&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Makes &lt;strong&gt;component creation&lt;/strong&gt; use Angular 22’s Type-based API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;postinstall&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Makes the bridge &lt;strong&gt;repeatable&lt;/strong&gt; on every clean install / CI machine&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Without all three, you usually fix one crash and discover the next on the first snackbar or dialog.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Step-by-step implementation guide
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 0 — Decide this is temporary debt
&lt;/h3&gt;

&lt;p&gt;Write down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why Material cannot move yet&lt;/li&gt;
&lt;li&gt;Who owns the follow-up Material upgrade&lt;/li&gt;
&lt;li&gt;Target removal sprint / release&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you cannot answer those, do not ship the shim.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 — Pin versions intentionally
&lt;/h3&gt;

&lt;p&gt;Keep core and CDK majors explicit in &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@angular/core"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^22.1.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@angular/cdk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16.2.14"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@angular/material"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16.2.14"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prefer an &lt;strong&gt;exact&lt;/strong&gt; CDK / Material pin (no &lt;code&gt;^&lt;/code&gt;) while the shim exists, so a minor CDK bump does not silently invalidate your string replacements.&lt;/p&gt;

&lt;p&gt;Use whatever peer-deps strategy your team already uses (&lt;code&gt;legacy-peer-deps&lt;/code&gt;, overrides, etc.). Peer warnings alone are not the fix — the runtime bridge is.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 — Confirm the failure is the factory gap
&lt;/h3&gt;

&lt;p&gt;Reproduce with a minimal Overlay / Dialog / SnackBar path. Confirm the stack involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@angular/cdk/overlay&lt;/code&gt; or &lt;code&gt;@angular/cdk/portal&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Missing / undefined &lt;code&gt;ComponentFactoryResolver&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Or &lt;code&gt;createComponent&lt;/code&gt; receiving a factory&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3 — Add an idempotent postinstall patch script
&lt;/h3&gt;

&lt;p&gt;Create something like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;scripts/patch-angular-22-cdk-compat.mjs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Design rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Idempotent&lt;/strong&gt; — running twice must be a no-op (use unique markers).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fail loud&lt;/strong&gt; — if Angular / CDK bundle shape changes, throw instead of silently doing nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No secrets&lt;/strong&gt; — only patch known public package files under &lt;code&gt;node_modules&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic&lt;/strong&gt; — same input packages → same output.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Wire it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"postinstall"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node scripts/patch-angular-22-cdk-compat.mjs"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4 — Shim &lt;code&gt;ComponentFactoryResolver&lt;/code&gt; back onto &lt;code&gt;@angular/core&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;node_modules/@angular/core/fesm2022/core.mjs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Insert a small class that:

&lt;ul&gt;
&lt;li&gt;Is &lt;code&gt;providedIn: 'root'&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Implements &lt;code&gt;resolveComponentFactory(componentType)&lt;/code&gt; using Angular’s internal component definition helpers still present in the bundle&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Re-export &lt;code&gt;ComponentFactoryResolver&lt;/code&gt; from the public export list&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This restores the &lt;strong&gt;DI token&lt;/strong&gt;. It does not by itself make every portal attach path correct.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5 — Patch CDK portal attach paths
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;node_modules/@angular/cdk/fesm2022/portal.mjs&lt;/code&gt;, update three call sites:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;DomPortalOutlet&lt;/code&gt; with &lt;code&gt;ViewContainerRef&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;DomPortalOutlet&lt;/code&gt; without &lt;code&gt;ViewContainerRef&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;CdkPortalOutlet&lt;/code&gt;&lt;/strong&gt; (SnackBar and template portals)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Replace factory-based creation with Type-based creation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6 — Clear stale prebundles
&lt;/h3&gt;

&lt;p&gt;Angular’s Vite-based serve cache can keep &lt;strong&gt;old&lt;/strong&gt; prebundled CDK copies. After patching, delete the relevant Vite deps cache under &lt;code&gt;.angular/cache&lt;/code&gt; (or restart with a clean cache) so &lt;code&gt;ng serve&lt;/code&gt; loads patched files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7 — Verify the high-risk UI surfaces
&lt;/h3&gt;

&lt;p&gt;At minimum:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] App bootstrap&lt;/li&gt;
&lt;li&gt;[ ] MatDialog open / close&lt;/li&gt;
&lt;li&gt;[ ] MatMenu / select overlays&lt;/li&gt;
&lt;li&gt;[ ] MatSnackBar with custom component content&lt;/li&gt;
&lt;li&gt;[ ] MatBottomSheet / sidenav overlays if used&lt;/li&gt;
&lt;li&gt;[ ] Custom CDK &lt;code&gt;Overlay&lt;/code&gt; + &lt;code&gt;ComponentPortal&lt;/code&gt; directives&lt;/li&gt;
&lt;li&gt;[ ] Tabs that dynamically create content&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 8 — Document the debt in the repo
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;README&lt;/code&gt; or an ADR:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why the shim exists&lt;/li&gt;
&lt;li&gt;Which Angular / CDK versions it targets&lt;/li&gt;
&lt;li&gt;How to remove it when Material is upgraded&lt;/li&gt;
&lt;li&gt;Who to ping when &lt;code&gt;postinstall&lt;/code&gt; starts failing&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  7. What each patch does (deep dive)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Patch A — Core shim (DI compatibility)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; CDK Overlay injects &lt;code&gt;ComponentFactoryResolver&lt;/code&gt;. Token missing → crash at construction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Provide a root injectable with the same name/token and a &lt;code&gt;resolveComponentFactory&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it must not do:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Invent a second Angular runtime&lt;/li&gt;
&lt;li&gt;Monkey-patch unrelated DI tokens&lt;/li&gt;
&lt;li&gt;Hide unrelated upgrade errors&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Patch B — DomPortalOutlet + ViewContainerRef
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before (CDK 16):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;componentRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;viewContainerRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;componentFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;viewContainerRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;injector&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;viewContainerRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectableNodes&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (Angular 22-compatible):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;componentRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;viewContainerRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;viewContainerRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;injector&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;viewContainerRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;projectableNodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectableNodes&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Patch C — DomPortalOutlet without ViewContainerRef
&lt;/h3&gt;

&lt;p&gt;Some attaches (including certain snackbar / overlay container paths) call &lt;code&gt;componentFactory.create(...)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;componentRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;environmentInjector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_appRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;elementInjector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;injector&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_defaultInjector&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;Injector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;projectableNodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectableNodes&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to import &lt;code&gt;createComponent&lt;/code&gt; from &lt;code&gt;@angular/core&lt;/code&gt; in the portal bundle if it is not already imported.&lt;/p&gt;

&lt;h3&gt;
  
  
  Patch D — CdkPortalOutlet
&lt;/h3&gt;

&lt;p&gt;This is the path many teams miss. SnackBar custom content often fails here even after DomPortalOutlet looks “fixed.”&lt;/p&gt;

&lt;p&gt;Replace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;resolver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolveComponentFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;viewContainerRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;componentFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;viewContainerRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  8. How the runtime flow works (visual)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before the bridge (broken)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fplhrg8so6nikiddb4a49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fplhrg8so6nikiddb4a49.png" alt=" " width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  After the bridge (working)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcxjguq7jit5wly7j4ba2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcxjguq7jit5wly7j4ba2.png" alt=" " width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Install-time flow
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flhdflpx3172l3ed0wpkg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flhdflpx3172l3ed0wpkg.png" alt=" " width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Prefer also opening the interactive companion visualization in Cursor if you are reading this from the engineering workspace — it animates the same flows step by step.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  9. Pros and cons
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Benefit&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Unblocks Angular 22 core upgrade&lt;/td&gt;
&lt;td&gt;Security / ecosystem / TypeScript 6 alignment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Avoids a big-bang Material rewrite&lt;/td&gt;
&lt;td&gt;UI risk stays in a dedicated follow-up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Localized change&lt;/td&gt;
&lt;td&gt;Mostly &lt;code&gt;node_modules&lt;/code&gt; patching + one script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI-reproducible&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;postinstall&lt;/code&gt; applies on every clean install&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incremental verification&lt;/td&gt;
&lt;td&gt;You can validate Overlay surfaces before Material migration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;Why it hurts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Unsupported configuration&lt;/td&gt;
&lt;td&gt;Angular does not promise this pairing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fragile string patches&lt;/td&gt;
&lt;td&gt;CDK / core FESM shape can change on patch releases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hidden debt&lt;/td&gt;
&lt;td&gt;New hires may not know why &lt;code&gt;postinstall&lt;/code&gt; exists&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dual mental models&lt;/td&gt;
&lt;td&gt;App code on Angular 22 APIs; UI kit on Angular 16 APIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache footguns&lt;/td&gt;
&lt;td&gt;Stale Vite prebundles look like “random” regressions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slows Material urgency&lt;/td&gt;
&lt;td&gt;Temporary fixes become permanent if no removal plan&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Bottom line:&lt;/strong&gt; Great as a &lt;strong&gt;bridge&lt;/strong&gt;. Expensive as a &lt;strong&gt;destination&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Best practices when you force this compatibility
&lt;/h2&gt;

&lt;p&gt;These practices matter precisely because the solution is forceful.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Pin exact CDK / Material versions
&lt;/h3&gt;

&lt;p&gt;Do not float on &lt;code&gt;^16.2.14&lt;/code&gt; while the patch depends on exact source strings.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Keep the patch script boring and strict
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Unique markers for every edit&lt;/li&gt;
&lt;li&gt;Throw on unexpected file shape&lt;/li&gt;
&lt;li&gt;Log success / already-applied / failure clearly&lt;/li&gt;
&lt;li&gt;Never “best effort” swallow errors in CI&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Treat &lt;code&gt;postinstall&lt;/code&gt; failures as build failures
&lt;/h3&gt;

&lt;p&gt;If the shim cannot apply, &lt;strong&gt;fail the pipeline&lt;/strong&gt;. Shipping an unpatched tree is worse than a red build.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Add a smoke suite for Overlay surfaces
&lt;/h3&gt;

&lt;p&gt;Automate dialog, menu, snackbar, and custom portal opens in CI. Unit tests alone rarely catch this.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Separate “core upgrade” PRs from “Material upgrade” PRs
&lt;/h3&gt;

&lt;p&gt;Reviewers need a clean story:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PR A: Angular 22 + compatibility bridge&lt;/li&gt;
&lt;li&gt;PR B: Material / CDK upgrade + delete bridge&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Do not spread shims into application code
&lt;/h3&gt;

&lt;p&gt;Prefer patching the boundary (core export + CDK portal) over sprinkling fake providers across feature modules. One bridge is easier to delete than twenty local workarounds.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Record version matrix in an ADR
&lt;/h3&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Supported bridge matrix:
  @angular/core@22.1.x
  @angular/cdk@16.2.14
  @angular/material@16.2.14
Anything else = re-verify or remove the script.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  8. Plan the removal before merge
&lt;/h3&gt;

&lt;p&gt;A shim without a removal ticket is how temporary hacks become folklore.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Prefer official upgrades when feasible
&lt;/h3&gt;

&lt;p&gt;If Material can move in the same quarter, do that instead. The bridge is for when UI migration truly cannot keep pace with core.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Watch Angular / CDK release notes every bump
&lt;/h3&gt;

&lt;p&gt;Even a core patch release can reshape FESM output enough to break naive replacements.&lt;/p&gt;




&lt;h2&gt;
  
  
  11. Corner cases you must keep in mind
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SnackBar custom component content&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Often uses &lt;code&gt;CdkPortalOutlet&lt;/code&gt;, not only &lt;code&gt;DomPortalOutlet&lt;/code&gt;. Patch both.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Portals without ViewContainerRef&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The no-VCR branch needs &lt;code&gt;createComponent(...)&lt;/code&gt; with an &lt;code&gt;environmentInjector&lt;/code&gt;. Easy to miss.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Custom application code still using &lt;code&gt;ComponentFactoryResolver&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Search your &lt;code&gt;src/&lt;/code&gt; too. The shim may hide app debt that should be migrated properly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Legacy Material modules&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;MatLegacy*&lt;/code&gt; can surface more Overlay paths. Test legacy and non-legacy entry points.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multiple Angular copies&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If a dependency bundles another &lt;code&gt;@angular/core&lt;/code&gt;, your shim may patch the wrong copy. Deduplicate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;pnpm / Yarn / npm differences&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Patch paths assume classic &lt;code&gt;node_modules/@angular/...&lt;/code&gt; layout. Adapt for PnP or isolated linkers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Docker / CI clean installs&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Locally patched trees lie. Always validate from a fresh &lt;code&gt;npm ci&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vite / esbuild prebundle cache&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
After patching, clear Angular’s Vite deps cache or you will debug ghosts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SSR / non-browser platforms&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If you use Angular Universal or similar, verify overlay-heavy routes on server and client.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Animations module presence&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Overlay behavior can differ if animations providers are missing or duplicated.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Zone vs zoneless&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Timing bugs in overlays can look like “compat failures” under zoneless experiments. Isolate variables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Partial upgrades&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Updating only &lt;code&gt;@angular/material&lt;/code&gt; but not &lt;code&gt;@angular/cdk&lt;/code&gt; (or the reverse) can reintroduce skew inside the UI toolkit itself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Marker collisions&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If you fork the script across repos, keep marker comments unique and stable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security / supply chain reviews&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Some orgs flag &lt;code&gt;postinstall&lt;/code&gt; mutation of &lt;code&gt;node_modules&lt;/code&gt;. Document intent for AppSec.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Developer onboarding&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
“Delete node_modules and reinstall” must remain a safe recovery path — which is why idempotent &lt;code&gt;postinstall&lt;/code&gt; matters.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  12. Exit strategy: how to leave the shim behind
&lt;/h2&gt;

&lt;p&gt;When you are ready:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upgrade &lt;code&gt;@angular/cdk&lt;/code&gt; and &lt;code&gt;@angular/material&lt;/code&gt; to a major aligned with your Angular core.&lt;/li&gt;
&lt;li&gt;Run Material migrations / theme updates.&lt;/li&gt;
&lt;li&gt;Remove &lt;code&gt;postinstall&lt;/code&gt; patch script and markers.&lt;/li&gt;
&lt;li&gt;Grep the repo for shim markers and &lt;code&gt;ComponentFactoryResolver&lt;/code&gt; leftovers.&lt;/li&gt;
&lt;li&gt;Delete ADR “temporary” section or mark it superseded.&lt;/li&gt;
&lt;li&gt;Re-run the Overlay smoke suite on a clean install.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Success looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm ci
# no compatibility patch needed
ng serve / ng build / e2e overlays → green
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  13. Checklist before you ship
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Angular core on 22.x; CDK / Material pinned exactly&lt;/li&gt;
&lt;li&gt;[ ] Idempotent &lt;code&gt;postinstall&lt;/code&gt; patch committed&lt;/li&gt;
&lt;li&gt;[ ] Core CFR shim applies on clean install&lt;/li&gt;
&lt;li&gt;[ ] DomPortalOutlet with-VCR path patched&lt;/li&gt;
&lt;li&gt;[ ] DomPortalOutlet no-VCR path patched&lt;/li&gt;
&lt;li&gt;[ ] CdkPortalOutlet path patched&lt;/li&gt;
&lt;li&gt;[ ] Vite / Angular dependency cache strategy documented&lt;/li&gt;
&lt;li&gt;[ ] Dialog, Menu, SnackBar, custom Overlay smoke-tested&lt;/li&gt;
&lt;li&gt;[ ] CI fails if patch cannot apply&lt;/li&gt;
&lt;li&gt;[ ] ADR + removal ticket exist&lt;/li&gt;
&lt;li&gt;[ ] No confidential internal names required to understand the script&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  14. Conclusion
&lt;/h2&gt;

&lt;p&gt;Angular 22’s removal of &lt;code&gt;ComponentFactoryResolver&lt;/code&gt; is the right long-term cleanup. CDK / Material 16 still living on factory-based portals is the short-term reality for many large apps.&lt;/p&gt;

&lt;p&gt;You can bridge that gap by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Restoring a minimal &lt;strong&gt;DI-compatible shim&lt;/strong&gt; in &lt;code&gt;@angular/core&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Rewriting CDK &lt;strong&gt;portal attach&lt;/strong&gt; calls to Angular 22’s Type-based &lt;code&gt;createComponent&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Running that bridge from &lt;strong&gt;&lt;code&gt;postinstall&lt;/code&gt;&lt;/strong&gt; so every machine gets the same result&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do it deliberately. Pin versions. Fail loud. Test overlays. And schedule the Material upgrade that makes the bridge unnecessary.&lt;/p&gt;

&lt;p&gt;Temporary compatibility is engineering. Permanent unsupported skew is risk.&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://angular.dev/update-guide" rel="noopener noreferrer"&gt;Angular Update Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://angular.dev/reference/versions" rel="noopener noreferrer"&gt;Angular version compatibility&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/pull/67889" rel="noopener noreferrer"&gt;Angular PR: remove &lt;code&gt;ComponentFactoryResolver&lt;/code&gt; from API surface&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://angular.io/guide/deprecations" rel="noopener noreferrer"&gt;Angular deprecations history (factory APIs)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article describes a general compatibility pattern for Angular 22 + CDK/Material 16. Adapt paths and markers to your package manager and bundle layout. Validate on a clean install before production.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>cdk</category>
    </item>
  </channel>
</rss>
