<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~files/atom-premium.xsl"?>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedpress="https://feed.press/xmlns" xmlns:media="http://search.yahoo.com/mrss/" xmlns:podcast="https://podcastindex.org/namespace/1.0">
  <feedpress:locale>en</feedpress:locale>
  <link rel="hub" href="https://feedpress.superfeedr.com/"/>
  <logo>https://static.feedpress.com/logo/telerik-blogs-web-angular-61850c76637b3.jpg</logo>
  <title type="text">Telerik Blogs | Web | Angular</title>
  <subtitle type="text">The official blog of Progress Telerik - expert articles and tutorials for developers.</subtitle>
  <id>uuid:0d01b7ce-1000-4a4f-a145-a8e5281a895c;id=158</id>
  <updated>2026-09-02T08:08:54Z</updated>
  <link rel="alternate" href="https://www.telerik.com/"/>
  <link rel="self" type="application/atom+xml" href="https://feeds.telerik.com/blogs/web-angular"/>
  <entry>
    <id>urn:uuid:18a8c83a-19ac-4a74-b424-ebdf4033bd47</id>
    <title type="text">Create a Kendo UI for Angular Dinner Picker</title>
    <summary type="text">Sick of picking where to go for dinner? Build this little Angular app to help you choose!</summary>
    <published>2026-08-20T17:09:35Z</published>
    <updated>2026-09-02T08:08:54Z</updated>
    <author>
      <name>Jonathan Gamble </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17424575/create-kendo-ui-angular-dinner-picker"/>
    <content type="text"><![CDATA[<p><span class="featured">Sick of picking where to go for dinner? Build this little Angular app to help you choose!</span></p><p>Do you ever argue about where to eat? If you&rsquo;re like me, you can&rsquo;t think of places half the time, and you just wish someone would pick for you. Well, here you go!</p><p><img sf-image-responsive="true" src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-08/chrome_v90f4i218o.gif?sfvrsn=5c1916fc_2" height="717" style="max-width:100%;height:auto;" title="Angular Restaurant Picker" width="501" alt="Angular Restaurant Picker with options for dine-in or take-out" sf-size="382850" /></p><h2 id="tldr">TL;DR</h2><p>This app will create a random dinner picker from JSON data in Angular using Progress Kendo UI. You can choose from Takeout or Dine-in.</p><h2 id="setup">Setup</h2><p>Create a new <a target="_blank" href="https://angular.dev/">Angular</a>&nbsp;app:</p><pre class=" language-html"><code class="prism  language-html">ng new angular-dinner-picker
</code></pre><h3 id="get-a-kendo-ui-license">Get a Kendo UI License</h3><p>Log in to Progress and purchase a Kendo UI for Angular license, or try it for free.</p><p><img sf-image-responsive="true" src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-08/image.png?sfvrsn=bece1600_2" height="840" style="max-width:100%;height:auto;" title="Kendo UI License Key" width="1195" alt="Kendo UI License Key" sf-size="107716" /></p><p>Download the actual key, as you will need it later for deployment.</p><h3 id="install-kendo-ui-licensing">Install Kendo UI Licensing</h3><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">npm</span> i -S @progress/kendo-licensing
</code></pre><p>Then run:</p><pre class=" language-bash"><code class="prism  language-bash">npx kendo-ui-license activate
</code></pre><p>This will set up Kendo UI on your local machine for this project. Make sure you have a working license at this point, and to <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/licensing">follow the correct setup</a>.</p><h3 id="install-packages">Install Packages</h3><pre class=" language-bash"><code class="prism  language-bash">ng add @progress/kendo-angular-buttons
ng add @progress/kendo-angular-dropdowns
ng add @progress/kendo-angular-layout
</code></pre><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">npm</span> i -S <span class="token function">npm</span> <span class="token function">install</span> @angular/forms @progress/kendo-svg-icons @progress/kendo-theme-default
</code></pre><p> You may need to also install <code>@angular/localize</code>.</p><h3 id="install-tailwind">Install Tailwind</h3><p>Make sure Angular is configured for Tailwind. Follow the <a target="_blank" href="https://tailwindcss.com/docs/installation/framework-guides/angular">Tailwind Guide</a>.</p><h3 id="configure-styles">Configure Styles</h3><p>Make sure your styles are shown in <code>styles.css</code> correctly.</p><pre class=" language-bash"><code class="prism  language-bash">@import <span class="token string">'@progress/kendo-theme-default/dist/default-main.css'</span><span class="token punctuation">;</span>
@import <span class="token string">'tailwindcss'</span><span class="token punctuation">;</span>
</code></pre><h2 id="picker-component">Picker Component</h2><p>Generate a new picker component.</p><pre class=" language-bash"><code class="prism  language-bash">ng g c picker
</code></pre><h3 id="model">Model</h3><p>Create a model at <code>picker.model.ts</code>.</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">export</span> <span class="token function">type</span> RestaurantMode <span class="token operator">=</span> <span class="token string">'dine-in'</span> <span class="token operator">|</span> <span class="token string">'takeout'</span><span class="token punctuation">;</span>

<span class="token function">export</span> <span class="token function">type</span> Restaurant <span class="token operator">=</span> <span class="token punctuation">{</span>
  id: number<span class="token punctuation">;</span>
  name: string<span class="token punctuation">;</span>
  cuisine: string<span class="token punctuation">;</span>
  mode: RestaurantMode<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token function">export</span> <span class="token function">type</span> RestaurantModeFilter <span class="token operator">=</span> <span class="token string">'all'</span> <span class="token operator">|</span> RestaurantMode<span class="token punctuation">;</span>
</code></pre><h3 id="data">Data</h3><p>You can declare your data in the <code>restaurants.ts</code>. You could obviously get more sophisticated and import data from a database if you like.</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">import</span> <span class="token punctuation">{</span> Restaurant <span class="token punctuation">}</span> from <span class="token string">"./picker.model"</span><span class="token punctuation">;</span>

<span class="token function">export</span> const restaurants: Restaurant<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token punctuation">{</span>
    <span class="token string">"id"</span><span class="token keyword">:</span> 1,
    <span class="token string">"name"</span><span class="token keyword">:</span> <span class="token string">"Monjunis"</span>,
    <span class="token string">"cuisine"</span><span class="token keyword">:</span> <span class="token string">"Italian"</span>,
    <span class="token string">"mode"</span><span class="token keyword">:</span> <span class="token string">"dine-in"</span>
  <span class="token punctuation">}</span>,
  <span class="token punctuation">{</span>
    <span class="token string">"id"</span><span class="token keyword">:</span> 2,
    <span class="token string">"name"</span><span class="token keyword">:</span> <span class="token string">"Strawn's Eat Shop"</span>,
    <span class="token string">"cuisine"</span><span class="token keyword">:</span> <span class="token string">"Southern Diner"</span>,
    <span class="token string">"mode"</span><span class="token keyword">:</span> <span class="token string">"dine-in"</span>
  <span class="token punctuation">}</span>,
  <span class="token punctuation">{</span>
    <span class="token string">"id"</span><span class="token keyword">:</span> 3,
    <span class="token string">"name"</span><span class="token keyword">:</span> <span class="token string">"Country Tavern"</span>,
    <span class="token string">"cuisine"</span><span class="token keyword">:</span> <span class="token string">"BBQ"</span>,
    <span class="token string">"mode"</span><span class="token keyword">:</span> <span class="token string">"dine-in"</span>
  <span class="token punctuation">}</span>,
  
  <span class="token punctuation">..</span>.
  
<span class="token punctuation">]</span><span class="token punctuation">;</span>
</code></pre><p> I used my city&rsquo;s info so I can actually use the app! You can customize this and deploy it separately for different situations or cities!</p><h3 id="picker-class">Picker Class</h3><p>Create the picker classes at <code>picker.ts</code>.</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">import</span> <span class="token punctuation">{</span> ChangeDetectionStrategy, Component <span class="token punctuation">}</span> from <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token function">import</span> <span class="token punctuation">{</span> FormsModule <span class="token punctuation">}</span> from <span class="token string">'@angular/forms'</span><span class="token punctuation">;</span>

<span class="token function">import</span> <span class="token punctuation">{</span> ButtonsModule <span class="token punctuation">}</span> from <span class="token string">'@progress/kendo-angular-buttons'</span><span class="token punctuation">;</span>
<span class="token function">import</span> <span class="token punctuation">{</span> DropDownsModule <span class="token punctuation">}</span> from <span class="token string">'@progress/kendo-angular-dropdowns'</span><span class="token punctuation">;</span>

<span class="token function">import</span> <span class="token punctuation">{</span> restaurants <span class="token punctuation">}</span> from <span class="token string">'./restaurants'</span><span class="token punctuation">;</span>
<span class="token function">import</span> <span class="token punctuation">{</span> Restaurant, RestaurantModeFilter <span class="token punctuation">}</span> from <span class="token string">'./picker.model'</span><span class="token punctuation">;</span>

<span class="token function">type</span> ModeOption <span class="token operator">=</span> <span class="token punctuation">{</span>
  label: string<span class="token punctuation">;</span>
  value: RestaurantModeFilter<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

@Component<span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector: <span class="token string">'app-picker'</span>,
  standalone: true,
  imports: <span class="token punctuation">[</span>
    FormsModule,
    ButtonsModule,
    DropDownsModule
  <span class="token punctuation">]</span>,
  templateUrl: <span class="token string">'./picker.html'</span>,
  changeDetection: ChangeDetectionStrategy.OnPush
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token function">export</span> class Picker <span class="token punctuation">{</span>
  <span class="token function">readonly</span> restaurants <span class="token operator">=</span> restaurants<span class="token punctuation">;</span>

  <span class="token function">readonly</span> modeOptions: ModeOption<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      label: <span class="token string">'Any'</span>,
      value: <span class="token string">'all'</span>
    <span class="token punctuation">}</span>,
    <span class="token punctuation">{</span>
      label: <span class="token string">'Dine-in'</span>,
      value: <span class="token string">'dine-in'</span>
    <span class="token punctuation">}</span>,
    <span class="token punctuation">{</span>
      label: <span class="token string">'Takeout'</span>,
      value: <span class="token string">'takeout'</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">]</span><span class="token punctuation">;</span>

  selectedMode: RestaurantModeFilter <span class="token operator">=</span> <span class="token string">'all'</span><span class="token punctuation">;</span>
  selectedRestaurant: Restaurant <span class="token operator">|</span> null <span class="token operator">=</span> null<span class="token punctuation">;</span>

  get filteredRestaurants<span class="token punctuation">(</span><span class="token punctuation">)</span>: Restaurant<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>this.selectedMode <span class="token operator">==</span><span class="token operator">=</span> <span class="token string">'all'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> this.restaurants<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">return</span> this.restaurants.filter<span class="token punctuation">((</span>restaurant<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> restaurant.mode <span class="token operator">==</span><span class="token operator">=</span> this.selectedMode<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  pickRestaurant<span class="token punctuation">(</span><span class="token punctuation">)</span>: void <span class="token punctuation">{</span>
    const choices <span class="token operator">=</span> this.filteredRestaurants<span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>choices.length <span class="token operator">==</span><span class="token operator">=</span> 0<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      this.selectedRestaurant <span class="token operator">=</span> null<span class="token punctuation">;</span>
      <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    const pickableChoices <span class="token operator">=</span>
      this.selectedRestaurant <span class="token operator">&amp;&amp;</span> choices.length <span class="token operator">&gt;</span> 1
        ? choices.filter<span class="token punctuation">((</span>restaurant<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> restaurant.id <span class="token operator">!=</span><span class="token operator">=</span> this.selectedRestaurant?.id<span class="token punctuation">)</span>
        <span class="token keyword">:</span> choices<span class="token punctuation">;</span>

    const index <span class="token operator">=</span> Math.floor<span class="token punctuation">(</span>Math.random<span class="token punctuation">(</span><span class="token punctuation">)</span> * pickableChoices.length<span class="token punctuation">)</span><span class="token punctuation">;</span>

    this.selectedRestaurant <span class="token operator">=</span> pickableChoices<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><ul><li>Pick the restaurant with <code>pickResaturant()</code> function choosing a random JSON entry from the filtered results.</li><li>We have <code>any</code>, <code>dine-in</code> and <code>takeout</code>.</li><li>We will use the filtered results in the html template from <code>filteredResautrants()</code>.</li></ul><h3 id="picker-template">Picker Template</h3><pre class=" language-bash"><code class="prism  language-bash"><span class="token operator">&lt;</span>main
  class<span class="token operator">=</span><span class="token string">"grid min-h-screen place-items-center bg-[radial-gradient(circle_at_top,rgba(255,255,255,0.95),rgba(255,255,255,0)_28%),linear-gradient(180deg,#f7efe7_0%,#eef2f7_100%)] p-4 sm:p-6"</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>section
    class<span class="token operator">=</span><span class="token string">"w-full max-w-sm rounded-4xl border border-slate-300/40 bg-white/92 px-6 py-7 shadow-[0_24px_60px_rgba(15,23,42,0.12)] backdrop-blur-[14px] sm:px-8 sm:py-8"</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>header class<span class="token operator">=</span><span class="token string">"space-y-3 text-center"</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>h1 class<span class="token operator">=</span><span class="token string">"m-0 text-[2.05rem] font-semibold leading-[0.98] tracking-tight text-slate-800 sm:text-[2.3rem]"</span><span class="token operator">&gt;</span>
        Restaurant Picker
      <span class="token operator">&lt;</span>/h1<span class="token operator">&gt;</span>

      <span class="token operator">&lt;</span>p class<span class="token operator">=</span><span class="token string">"mx-auto max-w-64 text-[1rem] leading-7 text-slate-500"</span><span class="token operator">&gt;</span>
        Pick where to eat without thinking about it.
      <span class="token operator">&lt;</span>/p<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>/header<span class="token operator">&gt;</span>

    <span class="token operator">&lt;</span>div class<span class="token operator">=</span><span class="token string">"my-6 h-px bg-slate-200/80"</span><span class="token operator">&gt;</span><span class="token operator">&lt;</span>/div<span class="token operator">&gt;</span>

    <span class="token operator">&lt;</span>div class<span class="token operator">=</span><span class="token string">"space-y-6"</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>div class<span class="token operator">=</span><span class="token string">"space-y-3 text-center"</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>label for<span class="token operator">=</span><span class="token string">"mode"</span> class<span class="token operator">=</span><span class="token string">"block text-[1.15rem] font-semibold leading-tight text-slate-800"</span><span class="token operator">&gt;</span>
          What kind?
        <span class="token operator">&lt;</span>/label<span class="token operator">&gt;</span>

        <span class="token operator">&lt;</span>kendo-dropdownlist id<span class="token operator">=</span><span class="token string">"mode"</span> class<span class="token operator">=</span><span class="token string">"w-full text-left"</span> <span class="token punctuation">[</span>data<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"modeOptions"</span> textField<span class="token operator">=</span><span class="token string">"label"</span> valueField<span class="token operator">=</span><span class="token string">"value"</span>
          <span class="token punctuation">[</span>valuePrimitive<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"true"</span> <span class="token punctuation">[</span><span class="token punctuation">(</span>ngModel<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"selectedMode"</span> /<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>/div<span class="token operator">&gt;</span>

      <span class="token operator">&lt;</span>button kendoButton class<span class="token operator">=</span><span class="token string">"min-h-14 w-full text-base font-semibold"</span> themeColor<span class="token operator">=</span><span class="token string">"primary"</span> size<span class="token operator">=</span><span class="token string">"large"</span>
        rounded<span class="token operator">=</span><span class="token string">"large"</span> <span class="token punctuation">[</span>disabled<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"filteredRestaurants.length === 0"</span> <span class="token punctuation">(</span>click<span class="token punctuation">)</span><span class="token operator">=</span><span class="token string">"pickRestaurant()"</span><span class="token operator">&gt;</span>
        Pick Restaurant
      <span class="token operator">&lt;</span>/button<span class="token operator">&gt;</span>

      @if <span class="token punctuation">(</span>selectedRestaurant<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token operator">&lt;</span>section
        class<span class="token operator">=</span><span class="token string">"rounded-[1.75rem] border border-rose-200/80 bg-[linear-gradient(135deg,rgba(255,241,242,0.92),rgba(255,255,255,0.98))] px-6 py-6 shadow-[inset_0_1px_0_rgba(255,255,255,0.7)]"</span>
        aria-live<span class="token operator">=</span><span class="token string">"polite"</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>div class<span class="token operator">=</span><span class="token string">"grid justify-items-center gap-4 text-center"</span><span class="token operator">&gt;</span>
          <span class="token operator">&lt;</span>p class<span class="token operator">=</span><span class="token string">"m-0 text-[0.78rem] font-bold uppercase tracking-[0.2em] text-rose-700"</span><span class="token operator">&gt;</span>Tonight<span class="token string">'s pick&lt;/p&gt;

          &lt;h2
            class="m-0 max-w-[11ch] text-[clamp(1.7rem,4vw,2rem)] font-semibold leading-[1.08] tracking-tight text-slate-900 text-balance"&gt;
            {{ selectedRestaurant.name }}
          &lt;/h2&gt;

          &lt;div class="grid justify-items-center gap-3"&gt;
            &lt;p class="m-0 text-[1rem] leading-6 text-slate-700"&gt;
              {{ selectedRestaurant.cuisine }}
            &lt;/p&gt;

            &lt;span
              class="inline-flex min-h-10 items-center justify-center rounded-full border border-slate-300/40 bg-white/90 px-5 text-sm font-bold text-slate-900 shadow-[0_6px_18px_rgba(15,23,42,0.06)]"&gt;
              {{ selectedRestaurant.mode === '</span>dine-in<span class="token string">' ? '</span>Dine-in<span class="token string">' : '</span>Takeout<span class="token string">' }}
            &lt;/span&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
      } @else {
      &lt;div
        class="rounded-[1.75rem] border border-dashed border-slate-400/60 bg-slate-50/75 px-5 py-6 text-center text-[0.95rem] leading-6 text-slate-500"&gt;
        @if (filteredRestaurants.length === 0) {
        No restaurants found for this option.
        } @else {
        Click the button to pick a restaurant.
        }
      &lt;/div&gt;
      }

      &lt;p class="text-center text-[0.82rem] font-semibold text-slate-500"&gt;
        {{ filteredRestaurants.length }}
        restaurant{{ filteredRestaurants.length === 1 ? '</span><span class="token string">' : '</span>s' <span class="token punctuation">}</span><span class="token punctuation">}</span> available
      <span class="token operator">&lt;</span>/p<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>/div<span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>/section<span class="token operator">&gt;</span>
<span class="token operator">&lt;</span>/main<span class="token operator">&gt;</span>
</code></pre><p>Here&rsquo;s what&rsquo;s going on above:</p><ul><li>When we run <code>pickRestaurant()</code>, the app displays the filtered items as a signal.</li><li>The <code>kendo-dropdownlist</code> component uses <code>data</code> field for options with <code>label</code> and <code>value</code> matching the drop down.</li><li>We just add <code>kendoButton</code> to our <code>button</code> component to get the look we want. We can use Tailwind with the look!</li></ul><p>And it&rsquo;s that simple!</p><p><strong>Repo:</strong> <a target="_blank" href="https://github.com/jdgamble555/angular-dinner-picker">GitHub</a><br /><strong>Demo:</strong> <a target="_blank" href="https://angular-dinner-picker.vercel.app/">Vercel Serverless</a></p><p>You can try all of this yourself with the Kendo UI for Angular trial, free for 30 days.</p><p><a href="https://www.telerik.com/try/kendo-angular-ui" target="_blank" class="Btn">Try Now</a></p><img src="https://feeds.telerik.com/link/23055/17424575.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:6baa7763-d9fc-430d-8c59-6719df533ba5</id>
    <title type="text">Biometric Authentication in Angular Using Auth0</title>
    <summary type="text">Learn to build an authentication system that supports passkeys using the Auth0 SDK within an Angular application.</summary>
    <published>2026-08-03T12:17:02Z</published>
    <updated>2026-09-02T08:08:54Z</updated>
    <author>
      <name>Christian Nwamba </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17403333/biometric-authentication-angular-using-auth0"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn to build an authentication system that supports passkeys using the Auth0 SDK within an Angular application.</span></p><p>Passkeys combine both possession and inherence factors (hardware and biometrics) in a single authentication method. Basically, passkeys are public key cryptographic credentials that conform to FIDO protocols that provide strong, phishing-resistant authentication unlike regular password-based systems. They also sync across your devices, so you can easily sign in from your phone, laptop or tablet.</p><p>Building an authentication system or updating an existing one to support passkeys takes a lot of time. As a developer, you need to understand complex specs and get everything right. Identity providers like <a target="_blank" href="https://auth0.com/">Auth0</a> provide an easy-to-use suite of tools that allows you to build great authentication solutions that support the latest password-based to passwordless authentication methods without writing complicated code.</p><p>The goal of this article is to show how easy it is to build an authentication system that supports passkeys using the Auth0 SDK within an Angular application.</p><h2 id="prerequisites">Prerequisites</h2><p>To follow along with this guide, you need to be familiar with the <a target="_blank" href="https://angular.dev/">Angular</a> framework, have integrated or consumed RESTful APIs, and have a basic understanding of how authentication and authorization work.</p><h2 id="project-setup">Project Setup</h2><p>Let&rsquo;s create an Angular project by running the following command:</p><pre class=" language-shell"><code class="prism  language-shell">ng new ng-webauthn
</code></pre><p>Follow the prompts and accept all the defaults. This creates an Angular project in a folder called <code>ng-webauthn</code>.</p><p>We&rsquo;ll install our dependencies after we set up Auth0. Open your terminal and start your application by running the following command:</p><pre class=" language-shell"><code class="prism  language-shell">npm run start
</code></pre><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/angular-application.png?sfvrsn=a7e0e79_2" title="Angular application running on localhost:4200" alt="Angular application running on localhost:4200" /></p><p>One key thing to notice here is that our application runs on localhost:4200 by default. We&rsquo;ll need this information when configuring our application on the Auth0 dashboard.</p><h2 id="setting-up-auth0">Setting Up Auth0</h2><p>Let&rsquo;s now set up Auth0 and integrate it into our application.</p><p>Visit the <a target="_blank" href="https://auth0.com/signup">Auth0 onboarding page</a> to create an account. On the dashboard click on <strong>Applications</strong> &gt; Create <strong>Application</strong>.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/creating-application-on-auth0-dashboard.png?sfvrsn=72358021_2" title="Creating an application on Auth0 dashboard" alt="Creating an application on Auth0 dashboard" /></p><p>Since we&rsquo;re integrating with Angular, we created a single-page application on the Auth0 dashboard with an arbitrary name: &ldquo;test-app.&rdquo; You can choose your preferred name.</p><p>Next, let&rsquo;s click on the settings tab to configure our application.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/configuring-application-callback.png?sfvrsn=c567b2ee_2" title="Configuring application callback and Logout URLs" alt="Configuring application callback and Logout URLs" /></p><p>As seen above, the <strong>Callback URLs</strong> and <strong>Logout URLs</strong> input fields accept a comma-separated list of candidate URLs that we can redirect the user to after they log in, sign up or sign out, respectively.</p><p>To understand why we need this, we need to understand the default recommended authentication method when using Auth0, hosted or universal login.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/hosted-or-universal-login.png?sfvrsn=8c8f0984_2" title="Hosted or Universal login in Auth0" alt="Hosted or Universal login in Auth0" /></p><p>In the universal login flow, when a user wants to authenticate in an application (e.g., our Angular SPA), they are redirected to a page that is hosted and managed by Auth0 servers. This page is only accessible when a valid candidate redirect URL is provided. If authentication is successful, the user is redirected back to the Angular application.</p><p>Now, let&rsquo;s install the dependencies we&rsquo;ll need. From the root of your Angular project, open your terminal and run the following command:</p><pre class=" language-shell"><code class="prism  language-shell">npm install @auth0/auth0-angular@2.x
</code></pre><p>Next, let&rsquo;s take some code from the <strong>Quick Start</strong> section to initialize our application. We&rsquo;ll start by updating the contents of the <code>app.config.ts</code> file to look like this:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> ApplicationConfig<span class="token punctuation">,</span> provideZoneChangeDetection <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> provideRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/router'</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span> routes <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./app.routes'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> provideAuth0 <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@auth0/auth0-angular'</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> appConfig<span class="token punctuation">:</span> ApplicationConfig <span class="token operator">=</span> <span class="token punctuation">{</span>
  providers<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token function">provideZoneChangeDetection</span><span class="token punctuation">(</span><span class="token punctuation">{</span> eventCoalescing<span class="token punctuation">:</span> <span class="token keyword">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">provideRouter</span><span class="token punctuation">(</span>routes<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">provideAuth0</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    domain<span class="token punctuation">:</span> <span class="token string">"YOUR-DOMAIN"</span><span class="token punctuation">,</span>
    clientId<span class="token punctuation">:</span> <span class="token string">"YOUR-CLIENT-ID"</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre><p>The <code>provideAuth0</code> function accepts an object representing the configuration for our Auth0 application, which includes our domain and client ID.</p><p>Our <code>domain</code> is a unique URL created for us by Auth0 when we created an account. The <code>clientID</code> is a unique identifier for the application. We can get these credentials in the <strong>Settings</strong> tab, as shown below.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/obtaining-credentials.png?sfvrsn=1ff6aeba_2" title="Obtaining credentials to setup Auth0" alt="Obtaining credentials to setup Auth0" /></p><p>The <code>provideAuth0</code> function internally exposes a service called <code>AuthService</code>, which will be available globally to all the other components in our application tree.</p><p>Next, update your <code>app.component.ts</code> file to look like this:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> CommonModule <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/common'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Component<span class="token punctuation">,</span> inject <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> AuthService <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@auth0/auth0-angular'</span><span class="token punctuation">;</span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-root'</span><span class="token punctuation">,</span>
  template<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`
    @if (auth.isLoading$ | async) {
      &lt;div&gt;Loading...&lt;/div&gt;
    } @else {
      @if ((auth.isAuthenticated$ | async) &amp;&amp; (auth.user$ | async); as user) {
        &lt;section class="profile"&gt;
          &lt;h1&gt;Profile&lt;/h1&gt;
          @if (user.picture) {
            &lt;img class="avatar" [src]="user.picture" [alt]="user.name || 'Profile photo'" /&gt;
          }
          &lt;div&gt;
            &lt;b&gt;Name&lt;/b&gt;
            &lt;p&gt;{{ user.name || user.nickname || '--' }}&lt;/p&gt;
            &lt;b&gt;Email&lt;/b&gt;
            &lt;p&gt;{{ user.email || '--' }}&lt;/p&gt;
            @if (user.email_verified !== undefined) {
              &lt;b&gt;Email verified&lt;/b&gt;
              &lt;p&gt;{{ user.email_verified ? 'Yes' : 'No' }}&lt;/p&gt;
            }
            @if (user.sub) {
              &lt;b&gt;User ID&lt;/b&gt;
              &lt;p&gt;{{ user.sub }}&lt;/p&gt;
            }
          &lt;/div&gt;
          &lt;button
            type="button"
            (click)="
              auth.logout({
                authorizationParams: { redirect_uri: 'http://localhost:4200' },
              })
            "
          &gt;
            Log out
          &lt;/button&gt;
        &lt;/section&gt;
      } @else {
        @if (auth.error$ | async; as error) {
          &lt;p&gt;Error: {{ error.message }}&lt;/p&gt;
        }
        &lt;button
          (click)="
            auth.loginWithRedirect({
              authorizationParams: {
                screen_hint: 'signup',
                redirect_uri: 'http://localhost:4200',
              },
            })
          "
        &gt;
          Sign Up
        &lt;/button&gt;
        &lt;button
          (click)="
            auth.loginWithRedirect({
              authorizationParams: { redirect_uri: 'http://localhost:4200' },
            })
          "
        &gt;
          Log In
        &lt;/button&gt;
      }
    }
  `</span></span><span class="token punctuation">,</span>
  styles<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  providers<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>CommonModule<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">AppComponent</span> <span class="token punctuation">{</span>
  auth <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>AuthService<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>To simplify our application, we won&rsquo;t be using any routes. All the code we need will be contained in the root app component.</p><p>We start by injecting the <code>AuthService</code>. We also imported the <code>CommonModule</code> to use the async pipe, since most of the properties of <code>AuthService</code> are observables.</p><p>In the template, we render different pieces of UI based on the authentication state:</p><ul><li>When loading, we display a loading message.</li><li>When the user is authenticated, we display the user&rsquo;s details with a button to log out.</li><li>If there is an error from the authentication flow, we display it on the screen.</li><li>Otherwise, the user is presented with two buttons to sign up or log in.</li></ul><p>Notice that when we trigger <code>loginWithRedirect</code> and <code>logout</code>, we additionally pass a <code>redirect_url</code> with a valid value as defined in the Callback URLs input field earlier when we configured our Auth0 app.</p><p>To see the running application, open your terminal and run the following command:</p><pre class=" language-shell"><code class="prism  language-shell">npm run start
</code></pre><h2 id="adding-support-for-passkeys">Adding Support for Passkeys</h2><p>In our current application, we can sign up and log in with email and password and use SSO, but passkeys are not yet supported. Thankfully, with Auth0 and its zero-code configuration, we no longer need to change any code to support passkeys. We just need to make a few tweaks in our dashboard to get it working.</p><p>Head over to the <strong>Database Connections</strong> section and choose the database connection associated with the app.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/database-connection.png?sfvrsn=d655d586_2" title="Database connection" alt="Database connection" /></p><p>A database connection is an abstracted term in Auth0. It represents the storage layer (database) that stores all user credentials and the configuration options for how we want to identify and authenticate users. By default, a database connection is automatically created when we create an Auth0 account.</p><p>In the <strong>Authentication Methods</strong> tab, click on <strong>Passkeys</strong> and enable passkeys.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/enabling-passkeys.png?sfvrsn=7625ad0e_2" title="Enabling passkeys" alt="Enabling passkeys" /></p><p>Passkey support may not be enabled immediately. Instead, you may be presented with a popup showing a checklist of tasks you need to fulfill to make it work, as shown below.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/checklist-for-passkeys.png?sfvrsn=30b3d807_2" title="Checklist before enabling passkeys" alt="Checklist before enabling passkeys" /></p><p>In our case, the only pending item is to enable identifier-first login flow. If you are wondering what this means, Auth0 has a concept called Authentication Profiles, which allow us to configure the universal login page&rsquo;s flow when a user wants to authenticate.</p><p>In <strong>Authentication</strong> &gt; <strong>Authentication Profile</strong>, proceed to enable identifier-first login and click Save, as shown below.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/identifier-first-login.png?sfvrsn=8f827dd4_2" title="Enabling identifier first login to use passkeys" alt="Enabling identifier first login to use passkeys" /></p><p>In the identifier-first authentication profile, during sign-up or login, the user is first prompted for their identifier (typically their email). Then, based on the authentication methods supported by the identifier, a decision is made whether the user needs to provide a password or proceed to use or create a passkey.</p><p>As of the time of writing, identifier-first authentication is the typical way we authenticate when signing in with Google or on Apple&rsquo;s App Store Connect, just to name a few examples. We typically provide our email first, and then the system decides whether we need to provide a password or use another method to authenticate.</p><p>Now that we have all the items on the checklist sorted, we can go ahead to enable passkey support. After clicking <strong>Save</strong>, notice that we have passkeys enabled.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/confirming-passkeys-enabled.png?sfvrsn=a17e64cb_2" title="Confirming that passkeys are enabled" alt="Confirming that passkeys are enabled" /></p><h2 id="using-passkeys-in-our-app">Using Passkeys in Our App</h2><p>We now have all the configurations needed to support passkeys. Let&rsquo;s head back and start our Angular application by running <code>npm run start</code>.</p><h2 id="the-signup-flow.">The Signup Flow</h2><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/the-signup-flow.gif?sfvrsn=80c65352_2" title="The signup flow" alt="The signup flow" /></p><p>Notice that, now during sign-up, we are first prompted to enter our email. The form gives us an opportunity to create a passkey or continue with a password.</p><p>If the user agrees to create a passkey, it triggers the WebAuthn registration ceremony, which is the sequence of steps required to create a passkey, and this is handled by Auth0 automatically. To give a sneak peek of what happens during the process, we&rsquo;ll also briefly discuss the three entities and the two FIDO protocols that make passkeys possible.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/fido-protocols.png?sfvrsn=cfaeb20_2" title="FIDO protocols: webAuthn and CTAP with supporting entities that make passkeys possible" alt="FIDO protocols: webAuthn and CTAP with supporting entities that make passkeys possible" /></p><p>The server (relying party) in the diagram above represents the server-side application that wants to enroll users for passkeys. It communicates with the webpage running on the client&rsquo;s device using the Web Authentication protocol over HTTP to send information about itself and the configuration required when creating or authenticating with passkeys. The client communicates with the authenticator following the low-level Client to Authenticator Protocol (CTAP) over USB or Bluetooth for roaming authenticators, or directly for platform authenticators.</p><p>Authenticators are hardware devices that create and persist the public key credentials representing the passkeys. Platform authenticators are authenticators built into a device (e.g., a MacBook&rsquo;s Touch ID or an iPhone&rsquo;s Face ID), while roaming authenticators are external to the user&rsquo;s device (e.g., a YubiKey). It is important to note that the interactions between these three entities varies depending on whether the user is creating passkeys (WebAuthn registration ceremony) or using passkeys to log in (WebAuthn authentication ceremony).</p><p>The following steps are involved during registration:</p><ol><li>Client clicks &ldquo;Continue with passkey.&rdquo;</li><li>Webpage requests credential creation options from Auth0 servers over HTTP.</li><li>Auth0 servers respond with credential creation options.</li><li>Client connects to authenticator by calling the <code>window.navigator.credentials.create()</code> method with the provided options.</li><li>The user is presented with a modal to verify their identity.</li><li>User verifies their identity using biometrics (Face ID, Touch ID, etc.), and the passkey is created.</li><li>The authenticator returns an attestation to the client, which then sends it to the server for verification.</li><li>If verification succeeds, a session is created for the user.</li></ol><h2 id="the-login-flow">The Login Flow</h2><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/passkey-configurations.png?sfvrsn=3ed52cb4_2" title="Passkey configurations mapping to universal login UI" alt="Passkey configurations mapping to universal login UI" /></p><p>During login, notice that we get autocomplete when entering the email. When we click the &ldquo;Continue with passkeys&rdquo; button to log in with passkeys and choose a passkey, we verify with a biometric gesture and we&rsquo;re logged in.<br />We need to note the following points that made this good UX possible, from both the configuration side on our Auth0 dashboard and the technical side of how passkeys work with the concept of resident keys.</p><p>First, the autocomplete and the &ldquo;Continue with passkey&rdquo; button are available because of the configuration we made on our dashboard earlier. This shows how simple it is to customize the authentication flow with passkeys with just a few tweaks.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/webauthn-auto-complete-attributes.png?sfvrsn=59232493_2" title="Webauthn auto-complete attribute" alt="Webauthn auto-complete attribute" /></p><p>Note that &ldquo;webauthn&rdquo; must be the entry in the autocomplete attribute, as shown above, to work correctly across different browsers.</p><p>Secondly, the autocomplete on the email input field is possible because of the <code>autocomplete="webauthn"</code> attribute on the input element, which allows the page to load any resident keys available for that domain.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/client-side-discoverable-keys.png?sfvrsn=eb67a609_2" title="Client-side discoverable keys are available in a pop-up after clicking continue with passkey" alt="Client-side discoverable keys are available in a pop-up after clicking continue with passkey" /></p><h2 id="resident-keys">Resident Keys</h2><p>During sign-up in the last section, when we created the passkey, Auth0 favored the client-side discoverable passkeys option (also known as resident keys). Resident keys are passkeys whose availability can be detected on the client side without asking the server for any information about which passkeys are available.</p><p>This addresses the problem of using server-side discoverable keys, which require the user to provide an identifier to enable the server to determine which passkeys they own. This method placed too much dependence on the server and hurt the login experience. With client-side discoverable keys, the user is able to log in just by clicking, without having to provide any information.</p><p>Tying it all together, let&rsquo;s briefly describe how the login flow works:</p><ul><li>Client visits the page. As soon as the page mounts, it requests authentication options from the server, and the authentication process is triggered. This loads the resident keys and enables autofill for passkeys.</li><li>Client clicks the passkey autocomplete option on the input field from the dropdown. <code>window.navigator.credentials.get()</code> is called with the options to connect to the authenticator.</li><li>User is prompted to verify using their biometrics. If it succeeds, an assertion response is generated and sent back to the client, which then sends it to the server for verification.</li><li>If the assertion response is verified, a session is created for the user.</li></ul><h2 id="best-practices-when-using-passkeys">Best Practices When Using Passkeys</h2><ul><li>Since passkeys created are scoped to a particular domain (also known as the relying party ID), when using passkeys in production we should try to always use a custom domain we own instead of the default domain Auth0 provides. Also note that changing domains will invalidate existing passkeys that are not scoped to the new domain.</li><li>For users who do not have a device that supports passkeys, it is important to support other authentication methods, such as email and password, as we already have in our project.</li><li>With progressive enrollment, which is enabled by default, users who are signed into our application with other methods will be intermittently prompted to enroll their devices and create passkeys.</li><li>Also, passkeys should only be enabled on one database connection on our Auth0 dashboard. This keeps all passkeys stored in a central storage location to help maintain consistency and avoid fragmentation.</li></ul><h2 id="conclusion">Conclusion</h2><p>Passkeys are being adopted by major companies like Amazon, Google, Apple, GitHub and Microsoft for security and ease of use. This guide provides an easy way to use providers like Auth0 to build robust authentication systems, using passkeys. Hopefully, this will serve as a reference point when you need to use passkeys in your future projects.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Building Component-Aware Production UIs with Angular and Kendo UI MCP</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Through <a target="_blank" href="https://www.telerik.com/blogs/building-component-aware-production-ui-angular-kendo-ui-mcp">MCP, we can use component-aware AI</a> to help us build user interfaces in conjunction with our favorite component libraries. See it in Angular!</p></div></div></aside><img src="https://feeds.telerik.com/link/23055/17403333.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:82ce8902-8991-4cbb-affc-7ca6326db284</id>
    <title type="text">What Enterprise Teams Actually Look for in an Angular UI Library</title>
    <summary type="text">See what mattered when a real enterprise team was exploring which Angular component library to use, and what keeps them using Kendo UI.</summary>
    <published>2026-07-28T12:57:08Z</published>
    <updated>2026-09-02T08:08:54Z</updated>
    <author>
      <name>Petra Lazarova </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17390035/what-enterprise-teams-actually-look-for-angular-ui-library"/>
    <content type="text"><![CDATA[<p><span class="featured">See what mattered when a real enterprise team was exploring which Angular component library to use, and what keeps them using Kendo UI.</span></p><p><em>Editor&rsquo;s note: To respect our customer&rsquo;s privacy, some identifying details have been generalized while preserving technical insights and direct quotes from our conversation.</em></p><h2 id="tldr-what-enterprises-need-in-an-angular-library">TL;DR What Enterprises Need in an Angular Library</h2><p>Based on a conversation with an IT System Developer at an enterprise financial organization, five factors consistently influenced the team&rsquo;s evaluation of an Angular UI library:</p><ul><li>An enterprise-grade Angular data grid</li><li>A complete Angular component library</li><li>Documentation and API examples that keep developers productive</li><li>Reusable theming across multiple applications</li><li>Predictable upgrades and long-term stability</li></ul><p>While this conversation focused on Progress Kendo UI for Angular, these evaluation principles apply broadly to enterprise Angular applications.</p><p><img sf-image-responsive="true" src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/what-enterprise-teams-need-in-an-angular-ui-library.png?sfvrsn=573b6b_2" height="1536" style="max-width:100%;height:auto;" title="What Enterprise Teams Need in an Angular UI Library" width="1024" alt="What Enterprise Teams Need in an Angular UI Library" sf-size="1495956" /></p><h2 id="intro">Intro</h2><p>When Angular UI libraries are compared, the conversation usually starts with feature lists, demos and the latest capabilities. But that&rsquo;s rarely where enterprise teams stop.</p><p>During a recent conversation with an IT System Developer at an enterprise financial organization, we noticed something interesting. The discussion kept returning to the same themes: an enterprise-grade grid, a complete Angular component library, documentation developers can rely on, reusable theming and predictable upgrades.</p><p>None of those topics are particularly flashy. Together, they reveal what experienced engineering teams often optimize for: not just what an Angular UI library can do today, but how it supports development over the years that follow.</p><h2 id="the-grid-is-key-but-the-whole-ecosystem-matters">The Grid Is Key, But the Whole Ecosystem Matters</h2><p>For this team, the <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/grid">Angular DataGrid</a> wasn&rsquo;t simply another component. It was at the center of many of their internal business applications and the first thing they evaluated.</p><blockquote><p>&ldquo;The demand is to have a very good and advanced grid, because we use grids all over in our web applications, so that&rsquo;s the primary choice.&rdquo;</p></blockquote><p>Their applications depend on complex data workflows, including master-detail views, grouping, sorting, and cell and row editing. Having those capabilities available out of the box saved the team from building and maintaining them themselves.</p><p>At first glance, it would be easy to conclude that this was simply a grid decision. But it wasn&rsquo;t.</p><blockquote><p>&ldquo;We chose Kendo UI because of the Grid, but also because we use a wide variety of components.&rdquo;</p></blockquote><p>Those components include buttons, text inputs, checkboxes, labels, dropdowns, combo boxes, forms, dialogs, charts and more. Rather than combining multiple libraries, the team chose a single Angular component library that covered the majority of their application needs.</p><p>Cost was part of the conversation, too.</p><blockquote><p>&ldquo;We had to weigh the subscription cost, of course, but I think it&rsquo;s very professional, a portfolio of components, and it fits our needs very, very well.&rdquo;</p></blockquote><p>The Grid may have started the evaluation, but the broader ecosystem is what kept coming up throughout the conversation.</p><p><strong>Learn more: <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/grid">Explore the Kendo UI for Angular Data Grid.</a></strong></p><h2 id="documentation-goes-beyond-support-to-productivity">Documentation Goes Beyond Support to Productivity</h2><p>Documentation turned out to be just as important as the components themselves.</p><blockquote><p>&ldquo;I almost never need to write to you [Progress]. Your support site and your specification site are doing it for me. Usually, I find my answers in the API documentation and by looking at your examples.&rdquo;</p></blockquote><p>Good documentation doesn&rsquo;t replace support. It means developers rarely need support.</p><p>For this team, comprehensive API references and practical examples meant fewer interruptions, fewer support requests and less time searching for answers. Documentation wasn&rsquo;t something separate from the product. It was part of the development experience.</p><p><strong>Explore the documentation: <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/getting-started">Browse the Kendo UI for Angular docs &amp; demos.</a></strong></p><h2 id="consistency-matters-more-as-your-application-portfolio-grows">Consistency Matters More as Your Application Portfolio Grows</h2><p>The value of theming changes when you&rsquo;re maintaining multiple applications instead of just one. Rather than creating a new theme for every project, this team maintains a single reusable theme across its Angular applications.</p><blockquote><p>&ldquo;We do the same theme for all our web applications. So when we have done one, we can just copy the files to the next. And that&rsquo;s to eliminate work.&rdquo;</p></blockquote><p>That approach keeps branding consistent while eliminating repetitive work.</p><p>The team also shared a practical example from their upgrade experience.</p><blockquote><p>&ldquo;Earlier, trying to cope with the changes in the style sheets could take some time. We are using the new theme editor for that, so it&rsquo;s OK now.&rdquo;</p></blockquote><p>That&rsquo;s a subtle but important distinction. Progress ThemeBuilder isn&rsquo;t only about creating themes. It&rsquo;s about making those themes easier to maintain over time.</p><p><strong>Explore ThemeBuilder: <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/styling/theme-builder">Learn how to create and maintain reusable themes across Angular applications.</a></strong></p><h2 id="for-enterprise-teams-predictability-is-a-must-have">For Enterprise Teams, Predictability Is a Must-Have</h2><p>Business-critical applications need to keep working through framework upgrades, dependency updates and ongoing maintenance. When we asked about upgrades, the discussion wasn&rsquo;t about the newest features. It was about confidence.</p><blockquote><p>&ldquo;In relation to major release updates, it&rsquo;s very well tested.&rdquo;</p></blockquote><blockquote><p>&ldquo;There can be some minor changes we have to do, but most backwards compatibility is good.&rdquo;</p></blockquote><p>No software upgrade is completely frictionless. For this team, predictable releases and good backward compatibility mattered because they made upgrades easier to manage. Sometimes the best release isn&rsquo;t the one with the longest list of new features. It&rsquo;s the one that lets developers keep moving.</p><h2 id="enterprise-teams-evaluate-platforms-not-features">Enterprise Teams Evaluate Platforms, Not Features</h2><p>Feature lists are easy to compare, but long-term developer experience isn&rsquo;t. One thing became clear as the conversation unfolded: it never stayed on a single capability for very long.</p><ul><li>The Angular Data Grid solved one set of challenges.</li><li>Documentation kept developers productive.</li><li>Reusable theming reduced repetitive work across applications.</li><li>Stable releases made upgrades easier to manage.</li></ul><p>None of those capabilities tells the whole story on its own.</p><p>Together, they suggest a different way of evaluating an Angular UI library: it&rsquo;s easy to compare individual components, but it&rsquo;s much harder, and often much more valuable, to evaluate how an ecosystem supports a team over the lifetime of an application.</p><p>That isn&rsquo;t a phrase the developer used during our conversation. It&rsquo;s the conclusion we came away with after listening to what mattered most.</p><p>If there&rsquo;s one lesson other engineering teams can take from this conversation, it&rsquo;s this:</p><p>Don&rsquo;t just compare features. Compare how much engineering work a platform helps your team avoid tomorrow, next year and several years from now.</p><p><a target="_blank" href="https://www.telerik.com/try/kendo-angular-ui" class="Btn">Try Kendo UI for Angular</a></p><img src="https://feeds.telerik.com/link/23055/17390035.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:55d87d50-bd62-4a7e-8963-0392a696d082</id>
    <title type="text">The 10 Best Angular UI Grids</title>
    <summary type="text">TL;DR What’s the best Angular grid? For most enterprise Angular applications, Progress Kendo UI for Angular Grid is the strongest all-around choice. It combines high-performance data handling, virtualization, AI-assisted features, theming tools and integration with a broader UI component library.</summary>
    <published>2026-07-20T17:36:42Z</published>
    <updated>2026-09-02T08:08:54Z</updated>
    <author>
      <name>Dany Paredes </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17383440/10-best-angular-ui-grids"/>
    <content type="text"><![CDATA[<p><span class="featured"><strong>TL;DR What&rsquo;s the best Angular grid?</strong> For most enterprise Angular applications, Progress Kendo UI for Angular Grid is the strongest all-around choice. It combines high-performance data handling, virtualization, AI-assisted features, theming tools and integration with a broader UI component library.</span></p><p>On the internet, data is everything. Since the beginning of the web, showing lists has been the standard way to present information.</p><p>We started with simple HTML tables, but over the years, displaying data has become much more than just creating a list. Today, it involves complex interactions and the need for data to travel smoothly between many different components.</p><p>In any application, when a list is slow or difficult to use, it is not just a small problem. It is a major blocker. A grid that cannot handle real-time updates does more than frustrate users; it can cause serious business problems and angry users.</p><p>In 2026, choosing a grid component is a business decision, not just a technical one. Modern <a target="_blank" href="https://www.telerik.com/blogs/angular-grid-scale-how-kendo-ui-handles-millions-rows">grids must handle thousands of rows</a>, update every second, export data for reports, integrate with AI agents and look good on all screens. You need all of this without making your developers write thousands of lines of custom code.</p><p>To understand why this matters, the best way is with a real-world scenario.</p><h2 id="the-scenario">The Scenario</h2><p>You have been hired by a startup to build a trading dashboard with real-time market data, thousands of rows updating constantly, complex filters, frozen columns, and one-click export to Excel. The CTO wants a working minimum viable product (MVP) ASAP to compete with time-to-market.</p><p>In this situation, your grid is the most important part of the product. Every second of lag or every missing feature is a threat to your deadline. If the grid fails during a demo with investors, the rest of the app does not matter.</p><blockquote><p><strong>Consider:</strong> Many teams waste half their time building basic features like virtual scrolling. However, the biggest problem is communication. A grid must talk to the rest of your app. When you mix different libraries for your grid and your buttons, making them work together is a nightmare.</p></blockquote><p>Let&rsquo;s look at the best options available today and see how they can help you and your team.</p><h2 id="kendo-ui-for-angular-grid">1. Kendo UI for Angular Grid</h2><p>No matter how small, large or complex your data is, the Progress Kendo UI for <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/grid/">Angular Grid</a> is the best choice when you need a grid that meets every requirement. It is built to handle everything from simple lists to massive enterprise datasets with real-time updates.</p><p>This component is not just powerful; it is also easy to customize. Because it is part of a complete suite, the grid integrates perfectly with other Kendo UI components like charts and dropdowns. This solves the &ldquo;headache&rdquo; of making different parts of your app talk to each other.</p><p>I have watched how building grids has evolved over many years. Based on that experience, here are the reasons why Kendo UI is the right choice for professional projects:</p><h3 id="why-kendo-ui-grid-is-the-right-choice-for-professional-projects">Why Kendo UI Grid is the Right Choice for Professional Projects</h3><ul><li><p><strong><a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/grid/smart-grid">Smart Grid and AI Assistant</a>:</strong> This is where Kendo UI really changes the game. It is not just a table; it is a &ldquo;smart&rdquo; component. With the <strong>AI Smart Box</strong>, users can use natural language to search, filter and manage data. Instead of looking for exact keywords, the <strong>Semantic Search</strong> understands what the user actually wants.</p></li><li><p><strong>AI-powered insights:</strong> The grid can highlight important rows and provide smart data summaries automatically. This helps users find the most important information without manual work.</p></li><li><p><strong>Virtual scrolling and row virtualization:</strong> The grid handles hundreds of thousands of rows easily. Scrolling is fast even when data changes constantly, which is essential for trading.</p></li><li><p><strong>Real-time data binding:</strong> It works excellently with live data streams. You can update the grid without refreshing the entire dataset, keeping the UI fast.</p></li><li><p><strong>Frozen columns and column management:</strong> You can pin important columns while users scroll horizontally through large datasets.</p></li><li><p><strong>Built-in Excel and PDF export:</strong> This is a native feature, not a third-party plugin. It keeps your styles, filters and column settings.</p></li><li><p><strong><a target="_blank" href="https://www.telerik.com/mcp-servers">MCP Server</a>:</strong> The Kendo UI MCP Server helps AI tools (like Cursor or Copilot) write better code by providing the correct patterns for the component.</p></li><li><p><strong><a target="_blank" href="https://themebuilder.telerik.com/">ThemeBuilder</a>:</strong> You can import Figma design tokens to make the grid match your brand perfectly without writing complex CSS.</p></li><li><p><strong><a target="_blank" href="https://www.telerik.com/purchase/support-plans">Expert support</a>:</strong> If you have a problem during a busy week, you can get help directly from the engineers who built the grid.</p></li></ul><p><strong>Pro tip:</strong> You can <a target="_blank" href="https://www.telerik.com/try/kendo-angular-ui">try the Kendo UI for Angular Grid for free</a> for 30 days. Test it with your real data before you decide.</p><div data-sf-ec-immutable="" class="-sf-relative" contenteditable="false" style="width:560px;height:600px;"><div data-sf-disable-link-event=""><iframe src="https://demos.telerik.com/kendo-angular-ui/demos/grid/filter-all-columns?theme=meridian-main" width="560" height="800" title="Kendo UI for Angular Grid example"></iframe></div></div><p>&nbsp;</p><p>If you have always worked within the official Angular ecosystem, the next option on this list will be very familiar to you.</p><h2 id="angular-material-table-cdk">2. Angular Material Table (CDK)</h2><p><a target="_blank" href="https://material.angular.io/">Angular Material</a> is the official UI library from the Angular team. Most Angular developers have used its table component.</p><ul><li><p><strong>The Good:</strong> It is very stable, updated frequently and follows Material Design standards. The Component Dev Kit (CDK) gives you a lot of flexibility.</p></li><li><p><strong>The Cons:</strong> You must build almost every feature yourself. Sorting, filtering, virtual scrolling and export are not included by default. For a project with a short deadline, this is too much work.</p></li><li><p><strong>My Feedback:</strong> Angular Material is a good starting point, but it is only a foundation. In a high-stakes project, you should not waste time building features that professional libraries have already solved.</p></li></ul><p>When you need a tool that focuses entirely on high-performance tables as a standalone component, you will likely look at the following library.</p><h2 id="ag-grid">3. AG Grid</h2><p><a target="_blank" href="https://www.ag-grid.com/angular-data-grid/">AG Grid</a> is a very popular standalone grid library. It is known for high performance and many enterprise features.</p><ul><li><p><strong>The Good:</strong> If your app is mostly about tables, AG Grid is very fast. The community version includes many features for free.</p></li><li><p><strong>The Cons:</strong> A real application needs more than just a grid. You will also need charts, date pickers and modals. AG Grid does not provide these. If you mix it with other libraries, it is difficult to keep the design and styling consistent.</p></li><li><p><strong>My Feedback:</strong> AG Grid is powerful, but it is a standalone tool. Kendo UI gives you the same power within a <strong>unified system</strong>. This means your grid, charts and dropdowns all use the same design and the same support team.</p></li></ul><p>For teams that prefer a large collection of components that are easy to implement, there is another very common choice in the community.</p><h2 id="primeng">4. PrimeNG</h2><p><a target="_blank" href="https://primeng.org/">PrimeNG</a> is a very complete library. Its <code>p-table</code> component is good for most standard use cases.</p><ul><li><p><strong>The Good:</strong> It has good documentation and is easy to start using. It works well for standard CRUD applications with medium-sized datasets.</p></li><li><p><strong>The Cons:</strong> For extreme scenarios, such as thousands of real-time updates, it can have performance issues. Virtual scrolling is available but requires more manual configuration.</p></li><li><p><strong>My Feedback:</strong> PrimeNG is a good choice for standard business apps. But for a fintech dashboard where the grid is the main product, you need a tool built for high performance from the start.</p></li></ul><p>As your project moves into the enterprise space with specific corporate requirements, you might consider an alternative that is widely used in large companies.</p><h2 id="syncfusion-angular-grid">5. Syncfusion Angular Grid</h2><p><a target="_blank" href="https://www.syncfusion.com/angular-ui-components/angular-grid">Syncfusion</a> offers an enterprise grid with many features like row grouping and PDF export.</p><ul><li><p><strong>The Good:</strong> It has a long list of features and handles large data well. It integrates well if you already use other Syncfusion tools.</p></li><li><p><strong>The Cons:</strong> The API does not always feel like standard Angular code, so there is a learning curve. Changing the design to match a Figma file can be difficult and slow.</p></li><li><p><strong>My Feedback:</strong> If your designers and developers need to work together daily, the difficulty in styling Syncfusion can be a problem. Progress <strong>ThemeBuilder</strong> makes this process much faster and more accurate in Kendo UI.</p></li></ul><p>Teams coming from a background in traditional software development often find that the next grid fits their existing mental model perfectly.</p><h2 id="devextreme-angular-datagrid">6. DevExtreme Angular DataGrid</h2><p><a target="_blank" href="https://js.devexpress.com/Angular/Documentation/Guide/UI_Components/DataGrid/Getting_Started_with_DataGrid/">DevExtreme</a> by DevExpress is a feature-rich grid often used in traditional enterprise software.</p><ul><li><p><strong>The Good:</strong> It is great for complex scenarios like master-detail views and multi-level grouping. It will feel familiar if your team has a background in .NET or WinForms.</p></li><li><p><strong>The Cons:</strong> Some of the patterns feel old for modern web development. Customizing the CSS to look modern can be a difficult task.</p></li><li><p><strong>My Feedback:</strong> Modern applications need to be fast and look current. DevExtreme&rsquo;s older patterns can slow down a team. The Kendo UI library uses a <strong>modern, Angular-native architecture</strong> that is easier to maintain.</p></li></ul><p>If your main priority is fast data visualization and specialized charts, there is a competitor that focuses heavily on those areas.</p><h2 id="ignite-ui-for-angular-grid">7. Ignite UI for Angular Grid</h2><p><a target="_blank" href="https://www.infragistics.com/products/ignite-ui-angular">Ignite UI</a> focuses on data visualization and high-performance grids.</p><ul><li><p><strong>The Good:</strong> The rendering engine is very fast and handles live updates well.</p></li><li><p><strong>The Cons:</strong> The community is smaller than other options. If you find a complex bug, it is harder to find answers or documentation.</p></li><li><p><strong>My Feedback:</strong> Performance is important, but support is also critical. The Kendo UI Grid offers similar performance but adds <strong>better documentation and a larger community</strong> to help you when you have problems.</p></li></ul><p>For developers who value a very clean design and a modular architecture based on modern TypeScript principles, there is an elegant solution to consider.</p><h2 id="taiga-ui-table">8. Taiga UI Table</h2><p><a target="_blank" href="https://taiga-ui.dev/">Taiga UI</a> is a modular library with a focus on TypeScript.</p><ul><li><p><strong>The Good:</strong> It has a very clean design. Because it is modular, you only use the code you need.</p></li><li><p><strong>The Cons:</strong> You have to build many features yourself. Virtual scrolling and export are not ready to use out of the box.</p></li><li><p><strong>My Feedback:</strong> Taiga UI is a great project, but it requires too much manual work for a short deadline. The Kendo UI library gives you <strong>120+ components that are already tested and ready to use</strong>.</p></li></ul><p>Some projects still use libraries that were very popular during the early versions of Angular and remain in many existing codebases.</p><h2 id="ng2-smart-table">9. ng2-smart-table</h2><p><a target="_blank" href="https://akveo.github.io/ng2-smart-table/">ng2-smart-table</a> was a very popular choice in the early days of Angular.</p><ul><li><p><strong>The Good:</strong> It is very simple to set up for basic tasks like sorting and filtering.</p></li><li><p><strong>The Cons:</strong> The library is not updated frequently anymore. This creates a risk of bugs or compatibility issues with new versions of Angular.</p></li><li><p><strong>My Feedback:</strong> Using a library that is no longer maintained creates &ldquo;technical debt.&rdquo; The Kendo UI library is supported by Progress Software, which means it receives <strong>regular updates and a clear roadmap</strong> you can trust.</p></li></ul><p>Finally, if your application requires a grid that behaves exactly like a spreadsheet instead of a standard list, there is a specialized tool for that specific case.</p><h2 id="handsontable">10. Handsontable</h2><p><a target="_blank" href="https://handsontable.com/">Handsontable</a> provides a spreadsheet-like experience (like Excel) in the browser.</p><ul><li><p><strong>The Good:</strong> It is the best choice if your users need to edit data like a spreadsheet (bulk edits, formulas, etc.).</p></li><li><p><strong>The Cons:</strong> The grid does not fully support Angular, works like a wrapper and is very limited (it also has a separate commercial license for bringing in Excel formulas features).</p></li><li><p><strong>My Feedback:</strong> Handsontable is perfect for spreadsheets, but a trading dashboard has different needs. The Kendo UI Grid provides the necessary Excel features while offering <strong>native Angular integration and real-time performance</strong>.</p></li></ul><h2 id="summary">Summary</h2><p>Today we learned how many good Angular grids exist, but when developers or agents in 2026 need to cover all the needs for your team and project, the list of options becomes much shorter. Mst grids on this list are good at one specific thing. However, for a project where the grid is the core of the product, you need a complete solution.</p><p>I pick the <strong>Kendo UI for Angular Grid</strong> as the best choice because it combines performance, features and design flexibility, and is also ready for the AI era with tools like the <strong><a target="_blank" href="https://www.telerik.com/mcp-servers">MCP Server</a></strong>.</p><p>When you have a short deadline, you need a tool that helps you work faster from day one and keeps the focus on building your product.</p><p>As I mentioned, Kendo UI for Angular comes with a free 30-day trial. So go ahead and poke around:</p><p><a target="_blank" href="https://www.telerik.com/try/kendo-angular-ui" class="Btn">Download Free Trial</a></p><img src="https://feeds.telerik.com/link/23055/17383440.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:4db51f4e-9e2e-4b06-9992-7768fc46c6f0</id>
    <title type="text">Async Validation in Angular Signal Forms</title>
    <summary type="text">Learn how to implement async validation in Angular Signal Forms using the validateHttp function, for example to check whether a username is already taken.</summary>
    <published>2026-07-14T11:38:56Z</published>
    <updated>2026-09-02T08:08:54Z</updated>
    <author>
      <name>Dhananjay Kumar </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17380028/async-validation-angular-signal-forms"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn how to implement async validation in Angular Signal Forms using the validateHttp function, for example to check whether a username is already taken.</span></p><p>Signal Forms create a form from a writable signal model, where the model is the source of truth, and any change in the form or the model is automatically reflected in the other.</p><p>Read more about <a href="https://www.telerik.com/blogs/getting-started-angular-signal-forms" target="_blank">Signal Forms here</a>.</p><p>In this article, we will explore async validation in Signal Forms. You perform async validation for various purposes, such as to:</p><ul><li>Check if usernames or emails are already taken</li><li>Look up data in the database to confirm values</li><li>Use external services (APIs) to verify things like addresses or tax IDs</li><li>Apply business rules that only the server can validate</li></ul><p>When creating a signup form, you need to check whether the email is already in use by calling a database via an API. Since this takes time, you should use Signal Forms async validation to handle it.</p><p>To validate against an API or HTTP endpoint, Angular provides the <code>validateHttp()</code> function. Let&rsquo;s explore how to use that.</p><h2 id="create-a-signup-form">Create a Signup Form</h2><p>To begin, create a signup form by first defining an interface to represent the signup type.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">SignupFormValue</span> <span class="token punctuation">{</span>
  readonly email<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
  readonly password<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Next, use it to create the signal-based Signup form as shown in the next code listing:</p><pre class=" language-ts"><code class="prism  language-ts">  signupModel<span class="token punctuation">:</span> WritableSignal<span class="token operator">&lt;</span>SignupFormValue<span class="token operator">&gt;</span> <span class="token operator">=</span> signal<span class="token operator">&lt;</span>SignupFormValue<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    email<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    password<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  signupForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>signupModel<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Then, in the template, bind it to the controls as shown below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">(submit)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>onSubmit($event)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>signup-email<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Email<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>signup-email<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>signupForm.email<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>signup-password<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Password<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>signup-password<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>signupForm.password<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Sign up<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Next, create the submit function as shown below.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">protected</span> <span class="token function">onSubmit</span><span class="token punctuation">(</span>event<span class="token punctuation">:</span> Event<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">submit</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>signupForm<span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> credentials <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">signupModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Signup submitted:'</span><span class="token punctuation">,</span> credentials<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre><p>As of now, we have created the signal-based signup form.</p><h2 id="adding-sync-validations">Adding Sync Validations</h2><p>To make it more usable, let us add some validations to the email field. We are going to add the validations below to the email field.</p><ol><li>Required</li><li>Email</li></ol><pre class=" language-ts"><code class="prism  language-ts">  signupForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>signupModel<span class="token punctuation">,</span> <span class="token punctuation">(</span>schemaPath<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schemaPath<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'Email is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">email</span><span class="token punctuation">(</span>schemaPath<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'Please enter a valid email address'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Both required and email are synchronous validators, and they run on each value change of controls. The <code>required()</code> validates that the control value is neither null nor an empty string (<code>''</code>), and <code>email()</code> validates the control value against a standard email regular expression pattern.</p><p>Both validators execute synchronously on each value change of the control.</p><p>We can conditionally show error messages for sync validators in the template using the field-state signals <code>touched()</code>, <code>invalid()</code> and <code>errors()</code>.</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token keyword">if</span> <span class="token punctuation">(</span>signupForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">touched</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> signupForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">invalid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token operator">&lt;</span>ul <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"error-list"</span><span class="token operator">&gt;</span>
      @<span class="token keyword">for</span> <span class="token punctuation">(</span>error <span class="token keyword">of</span> signupForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">errors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> track error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token operator">&lt;</span>li<span class="token operator">&gt;</span><span class="token punctuation">{</span><span class="token punctuation">{</span> error<span class="token punctuation">.</span>message <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>li<span class="token operator">&gt;</span>
      <span class="token punctuation">}</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>ul<span class="token operator">&gt;</span>
  <span class="token punctuation">}</span>
</code></pre><p>The <code>touched() &amp;&amp; invalid()</code> signals are used to show errors only after the user focuses and then blurs the field, so the form does not show errors on initial load.</p><h2 id="adding-async-validations">Adding Async Validations</h2><p>There are two ways you can add async validation to a signal form.</p><ol><li>Using <code>validateHttp()</code></li><li>Using <code>validateAysnc()</code></li></ol><p>In most cases, applications should use <code>validateHttp()</code> for asynchronous validation, as it simplifies HTTP-based validation with minimal configuration and supports most common scenarios.</p><p><code>validateAsync()</code> is a lower-level API that directly exposes Angular&rsquo;s resource primitive, providing full control over the validation process but requiring more implementation effort and a deeper understanding of the resource API.</p><p>Let&rsquo;s see how we can use <code>validateHttp()</code> to check whether an email exists or not .</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token function">validateHttp</span><span class="token punctuation">(</span>schemaPath<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span>
      request<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> value <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> emailValue <span class="token operator">=</span> <span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>emailValue<span class="token punctuation">)</span> <span class="token keyword">return</span> undefined<span class="token punctuation">;</span> <span class="token comment">// skip when empty</span>
        <span class="token keyword">return</span> <span class="token template-string"><span class="token string">`http://localhost:3000/user/check?email=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>emailValue<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      onSuccess<span class="token punctuation">:</span> <span class="token punctuation">(</span>response<span class="token punctuation">:</span> <span class="token punctuation">{</span> exists<span class="token punctuation">:</span> <span class="token keyword">boolean</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> response<span class="token punctuation">.</span>exists
          <span class="token operator">?</span> <span class="token punctuation">{</span>
              kind<span class="token punctuation">:</span> <span class="token string">'emailTaken'</span><span class="token punctuation">,</span>
              message<span class="token punctuation">:</span> <span class="token string">'This email is already registered'</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">:</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      onError<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
        kind<span class="token punctuation">:</span> <span class="token string">'serverError'</span><span class="token punctuation">,</span>
        message<span class="token punctuation">:</span> <span class="token string">'Could not verify email. Please try again later.'</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>We have an API that returns a response indicating whether the email already exists in the database, and we use the response&rsquo;s exists property to determine whether the email is already registered.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token punctuation">{</span>
  <span class="token string">"exists"</span><span class="token punctuation">:</span> <span class="token keyword">true</span><span class="token punctuation">,</span>
  <span class="token string">"user"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"id"</span><span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
    <span class="token string">"name"</span><span class="token punctuation">:</span> <span class="token string">"User 1"</span><span class="token punctuation">,</span>
    <span class="token string">"email"</span><span class="token punctuation">:</span> <span class="token string">"user1@example.com"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>We can show the pending state and error message from both sync and async validator as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token keyword">if</span> <span class="token punctuation">(</span>signupForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">pending</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token operator">&lt;</span>span <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"pending"</span><span class="token operator">&gt;</span>Checking email availability<span class="token operator">...</span><span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">&gt;</span>
  <span class="token punctuation">}</span>
  @<span class="token keyword">if</span> <span class="token punctuation">(</span>signupForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">touched</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> signupForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">invalid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token operator">&lt;</span>ul <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"error-list"</span><span class="token operator">&gt;</span>
      @<span class="token keyword">for</span> <span class="token punctuation">(</span>error <span class="token keyword">of</span> signupForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">errors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> track error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token operator">&lt;</span>li<span class="token operator">&gt;</span><span class="token punctuation">{</span><span class="token punctuation">{</span> error<span class="token punctuation">.</span>message <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>li<span class="token operator">&gt;</span>
      <span class="token punctuation">}</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>ul<span class="token operator">&gt;</span>
  <span class="token punctuation">}</span>
</code></pre><p>The validation flow works like this:</p><ul><li>User enters a value.</li><li>Synchronous validators run first.</li><li>If sync validation fails, async validation does not run.</li><li>If sync validation passes, async validation starts, and <code>pending()</code> becomes true.</li><li>Once the request completes, <code>pending()</code> becomes false.</li><li>Errors are updated based on the response.</li></ul><p>This can be put in a flow chart as shown below:</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/angular-signal-forms-validation-flow.png?sfvrsn=1b23b96b_2" alt="Angular Signal Form validation flow: User enters a value. Angular runs sync validators. If sync validation fails, show error message; if succeeds, Angular starts async validation and sets pending to true. Once request completes, pending becomes false. Errors are updated based on the response." /></p><p>Putting everything together, a signal-based signup form with both synchronous and asynchronous validators will look like this:</p><pre class=" language-ts"><code class="prism  language-ts">signupModel<span class="token punctuation">:</span> WritableSignal<span class="token operator">&lt;</span>SignupFormValue<span class="token operator">&gt;</span> <span class="token operator">=</span> signal<span class="token operator">&lt;</span>SignupFormValue<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    email<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    password<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  signupForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>signupModel<span class="token punctuation">,</span> <span class="token punctuation">(</span>schemaPath<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schemaPath<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'Email is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">email</span><span class="token punctuation">(</span>schemaPath<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'Please enter a valid email address'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">validateHttp</span><span class="token punctuation">(</span>schemaPath<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span>
      request<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> value <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> emailValue <span class="token operator">=</span> <span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>emailValue<span class="token punctuation">)</span> <span class="token keyword">return</span> undefined<span class="token punctuation">;</span> <span class="token comment">// skip when empty</span>
        <span class="token keyword">return</span> <span class="token template-string"><span class="token string">`http://localhost:3000/user/check?email=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>emailValue<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      onSuccess<span class="token punctuation">:</span> <span class="token punctuation">(</span>response<span class="token punctuation">:</span> <span class="token punctuation">{</span> exists<span class="token punctuation">:</span> <span class="token keyword">boolean</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> response<span class="token punctuation">.</span>exists
          <span class="token operator">?</span> <span class="token punctuation">{</span>
              kind<span class="token punctuation">:</span> <span class="token string">'emailTaken'</span><span class="token punctuation">,</span>
              message<span class="token punctuation">:</span> <span class="token string">'This email is already registered'</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">:</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      onError<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
        kind<span class="token punctuation">:</span> <span class="token string">'serverError'</span><span class="token punctuation">,</span>
        message<span class="token punctuation">:</span> <span class="token string">'Could not verify email. Please try again later.'</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">protected</span> <span class="token function">onSubmit</span><span class="token punctuation">(</span>event<span class="token punctuation">:</span> Event<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">submit</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>signupForm<span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> credentials <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">signupModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Signup submitted:'</span><span class="token punctuation">,</span> credentials<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre><p>And on the template, the pending state and error messages can be shown as below:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">(submit)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>onSubmit($event)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>signup-email<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Email<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>signup-email<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>signupForm.email<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>

  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
  @if (signupForm.email().pending()) {
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>pending<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Checking email availability...<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
  }
  @if (signupForm.email().touched() &amp;&amp; signupForm.email().invalid()) {
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>error-list<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      @for (error of signupForm.email().errors(); track error) {
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">&gt;</span></span>{{ error.message }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
      }
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">&gt;</span></span>
  }
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>signup-password<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Password<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>signup-password<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>signupForm.password<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Sign up<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
</code></pre><h2 id="validatehttp-function">validateHttp Function</h2><p>The <code>validateHttp</code> function contains three components:</p><ol><li>Request function</li><li>Success handler function</li><li>Error handler function</li></ol><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/angular-signal-form-validatehttp.png?sfvrsn=68791e3b_2" alt="Angular Signal Form validateHtep function components: request function, success handler function, error handler function" /></p><p>In the <code>validateHttp</code>, we have set the request function. It returns one of these three values:</p><ol><li>Undefined to skip the validation.</li><li>A URL for performing the validation using the GET operation.</li><li>An <code>HttpResourceRequest</code> if you need to set additional request options, such as the verb header, etc. This is the same object you use with <code>httpResource</code> to configure the request object.</li></ol><blockquote><p>Read more about the <a href="https://www.telerik.com/blogs/getting-started-httpresource-api-angular" target="_blank">httpResource here</a>.</p></blockquote><p>The <code>onSuccess</code> function receives the HTTP response and returns validation errors or undefined for valid values. It can also return multiple errors when needed.</p><p>The <code>onError</code> function handles request failures like network errors or HTTP errors.</p><p>If you need to validate an email using an endpoint with a POST request, custom headers and the email in the request body, you can do so by returning an <code>httpResourceRequest</code> from <code>validateHttp</code>, as shown below.</p><pre class=" language-ts"><code class="prism  language-ts">signupForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>signupModel<span class="token punctuation">,</span> <span class="token punctuation">(</span>schemaPath<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schemaPath<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'Email is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">email</span><span class="token punctuation">(</span>schemaPath<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'Please enter a valid email address'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token function">validateHttp</span><span class="token punctuation">(</span>schemaPath<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span>
      request<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> value <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> emailValue <span class="token operator">=</span> <span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>emailValue<span class="token punctuation">)</span> <span class="token keyword">return</span> undefined<span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token punctuation">{</span>
          url<span class="token punctuation">:</span> <span class="token string">'http://localhost:3000/user/check'</span><span class="token punctuation">,</span>
          method<span class="token punctuation">:</span> <span class="token string">'POST'</span><span class="token punctuation">,</span>
          body<span class="token punctuation">:</span> <span class="token punctuation">{</span> email<span class="token punctuation">:</span> emailValue <span class="token punctuation">}</span><span class="token punctuation">,</span>
          headers<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">'x-api-key'</span><span class="token punctuation">:</span> <span class="token string">'my-secret-key'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      onSuccess<span class="token punctuation">:</span> <span class="token punctuation">(</span>response<span class="token punctuation">:</span> <span class="token punctuation">{</span> exists<span class="token punctuation">:</span> <span class="token keyword">boolean</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> response<span class="token punctuation">.</span>exists
          <span class="token operator">?</span> <span class="token punctuation">{</span> kind<span class="token punctuation">:</span> <span class="token string">'emailTaken'</span><span class="token punctuation">,</span> message<span class="token punctuation">:</span> <span class="token string">'This email is already registered'</span> <span class="token punctuation">}</span>
          <span class="token punctuation">:</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      onError<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
        kind<span class="token punctuation">:</span> <span class="token string">'serverError'</span><span class="token punctuation">,</span>
        message<span class="token punctuation">:</span> <span class="token string">'Could not verify email. Please try again later.'</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The other function for async validation is <code>validateAsync()</code> function. It is a lower-level API that exposes Angular&rsquo;s resource primitive directly. It offers complete control but requires more code and familiarity with Angular&rsquo;s resource API. Most applications should use <code>validateHttp()</code>.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-07/angular-signal-form-validateasync.png?sfvrsn=91cb8667_2" alt="For Angular Signal Forms. Based on Resource API, validateAsync onSuccess, onError, params, factory." /></p><p>You should use <code>validateAsync()</code> for these purposes:</p><ul><li>Non-HTTP validation &ndash; WebSocket connections, IndexedDB lookups or Web Worker computations</li><li>Custom caching strategies &ndash; Application-specific caching beyond simple memorization</li><li>Complex retry logic &ndash; Custom backoff strategies or conditional retries</li><li>Direct resource access &ndash; When you need the full resource lifecycle</li></ul><p>In a future article, we&rsquo;ll take a deeper look at <code>validateAsync</code>. For now, I hope this gives you a clear understanding of how to implement async validation in Angular Signal Forms using the <code>validateHttp</code> function. Thanks for reading!</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Angular Signals: The Essentials You Need to Know</h4></div><div class="col-8"><p class="u-fs16 u-mb0"><a target="_blank" href="https://www.telerik.com/blogs/angular-signals-essentials-you-need-know">Angular Signals</a> mark a significant shift for the framework, not an optional feature. Learn more so you can keep up!</p></div></div></aside><img src="https://feeds.telerik.com/link/23055/17380028.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:23c4afbf-be58-4e27-8443-2bfe893aab86</id>
    <title type="text">Getting Started with Angular Signal Forms</title>
    <summary type="text">Learn the basics of Angular Signal Forms, including models, validation and two-way synchronization, to build reactive forms with confidence.</summary>
    <published>2026-07-07T12:13:00Z</published>
    <updated>2026-09-02T08:08:54Z</updated>
    <author>
      <name>Dhananjay Kumar </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17374360/getting-started-angular-signal-forms"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn the basics of Angular Signal Forms, including models, validation and two-way synchronization, to build reactive forms with confidence.</span></p><p>Angular version 21.0 introduced one of the most exciting and awaited features: Signal Forms. Traditionally, there have been two types of forms:</p><ol><li>Template Forms</li><li>Reactive Forms</li></ol><p>Angular 21.0 introduced a new form type:</p><ol start="3"><li>Signal Forms</li></ol><p>And now,&nbsp;<a href="https://www.telerik.com/blogs/angular-22-evolution-modern-angular" target="_blank">Angular 22</a> makes Signal Forms stable.&nbsp;Signal Forms are a combination of Signal-based reactivity and forms. In my opinion, Signal Forms are the future of forms and user input in Angular.</p><p>This article gives you a basic introduction to Signal Forms and shows you how to work with models, validation and two-way synchronization.</p><h2 id="first-signal-form">First Signal Form</h2><p>Signal-based forms use a new form function. It creates a form from a writable signal model, where the model is the source of truth, and any change in the form or the model is automatically reflected in the other.</p><p>Let&rsquo;s start by creating an interface to represent the user:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IUser</span> <span class="token punctuation">{</span>
    email<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
    password<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Next, we create a model that will be used to create the form, as shown below. As mentioned earlier, the model must be a writable signal.</p><pre class=" language-ts"><code class="prism  language-ts">user <span class="token punctuation">:</span> WritableSignal<span class="token operator">&lt;</span>IUser<span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    email<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    password<span class="token punctuation">:</span> <span class="token string">''</span>  
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre><p>We can create a signal-based form using the <code>form()</code> function from the <code>@angular/forms/signals</code>.</p><pre class=" language-ts"><code class="prism  language-ts">loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>That&rsquo;s it. You have created a signal-based form in Angular.</p><p>The form function returns a <code>FieldTree</code>, where each field is represented as a signal. In other words, the form function produces a data structure in which every field is a signal enriched with signal-based properties such as value, dirty, invalid and others.</p><p>To better understand this structure, let&rsquo;s print the following values:</p><pre class=" language-ts"><code class="prism  language-ts">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">loginForm</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">valid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">invalid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">dirty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">touched</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">errors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>As shown in the example above, the email field is a signal, and all of its properties are signals as well. Because both the field and its properties are signals, you can use them directly in the template, as demonstrated below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.email<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.password<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
</code></pre><p>To use <code>formField</code>, import it into the component class, as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> form<span class="token punctuation">,</span> FormField <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/forms/signals'</span><span class="token punctuation">;</span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-login'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>FormField<span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl<span class="token punctuation">:</span> <span class="token string">'./login.html'</span><span class="token punctuation">,</span>
  styleUrl<span class="token punctuation">:</span> <span class="token string">'./login.css'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Login</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre><p>As discussed earlier, the <code>form()</code> function creates a form from the given model, where the model is the single source of truth, so changes in the form update the model and changes in the model update the form.</p><p>In simple words, the model and the form are connected through two-way data binding. This means that when the model signal changes, the form value updates accordingly, and when the form value changes, the model updates as well.</p><p>To demonstrate this, read the model signal value inside an effect, as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  <span class="token function">effect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre><p>As soon as you start typing in the form, you can read the updated value in the effect. Similarly, when you change the model signal value, the form value is reflected as well.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">this</span><span class="token punctuation">.</span>user<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  email<span class="token punctuation">:</span> <span class="token string">'a@a.com'</span><span class="token punctuation">,</span>
  password<span class="token punctuation">:</span><span class="token string">'abc'</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">loginForm</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// updated value of the form</span>
</code></pre><p>In summary, in signal-based forms, the model used by the form and the form itself are connected via two-way data binding. Updating one automatically updates the other.</p><h3 id="adding-validations">Adding Validations</h3><p>The <code>form()</code> function in Signal Forms makes it simple to add validators to form fields. You can pass a schema function to the <code>form()</code> function to add validators to the form.</p><p>In Signal Forms, validations are defined using a schema function. You pass this schema function as the second parameter to the <code>form()</code> function.</p><p>You can add the required validators to the email and password fields as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">,</span><span class="token punctuation">(</span>schema<span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
  <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span><span class="token punctuation">{</span>message<span class="token punctuation">:</span><span class="token string">'email is required'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">email</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span><span class="token punctuation">{</span>message<span class="token punctuation">:</span><span class="token string">'email is not valid'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>password<span class="token punctuation">,</span><span class="token punctuation">{</span>message<span class="token punctuation">:</span><span class="token string">'password is required'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>We have added the required and email built-in validators and used the message option to provide custom error messages.</p><p>As discussed earlier, in a Signal Form, all properties of a field are signals. This allows you to use them directly. For example, to display validation error messages for the email field, as shown below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
  Email
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.email<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
@if (loginForm.email().invalid() &amp;&amp; loginForm.email().touched()) {
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>error<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    @for (error of loginForm.email().errors(); track error.kind) {
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>{{ error.message }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
    }
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
}
</code></pre><p>In the same way, error messages for the password field can be displayed as below:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
        Password
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.password<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
    @if (loginForm.password().invalid() &amp;&amp; loginForm.password().touched()) {
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>error<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        @for (error of loginForm.password().errors(); track error.kind) {
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>{{ error.message }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        }
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    }
</code></pre><h3 id="submitting-the-form">Submitting the Form</h3><p>To complete the form, you can add submit functionality by importing the <code>submit()</code> function and using that to submit the form.</p><pre class=" language-ts"><code class="prism  language-ts">  <span class="token function">onSubmit</span><span class="token punctuation">(</span>event<span class="token punctuation">:</span> Event<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">submit</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> u <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">userModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Logging in with:'</span><span class="token punctuation">,</span> u<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre><p>The <code>submit()</code> function runs the logic only when the form is valid.</p><p>In the template, the form submit event can bind to the <code>onSubmit ()</code> function using event binding, as shown below. You can also disable the submit button when the form is invalid.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">(submit)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>onSubmit($event)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    // other code for fields &hellip;..
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">[disabled]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm().invalid()<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Login<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
</code></pre><h3 id="complete-signal-based-login-form">Complete Signal-based Login Form</h3><p>Putting everything together, the login form using Signal Forms can be implemented as shown below.</p><p>The IUser interface is created as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IUser</span> <span class="token punctuation">{</span>
    email<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span> 
    password <span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span> 
<span class="token punctuation">}</span>
</code></pre><p>The Login component using a Signal Form is created as shown below.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component<span class="token punctuation">,</span> signal<span class="token punctuation">,</span> WritableSignal <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> IUser <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../user'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> email<span class="token punctuation">,</span> form<span class="token punctuation">,</span> FormField<span class="token punctuation">,</span> required<span class="token punctuation">,</span> submit <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/forms/signals'</span><span class="token punctuation">;</span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-login'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>FormField<span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl<span class="token punctuation">:</span> <span class="token string">'./login.html'</span><span class="token punctuation">,</span>
  styleUrl<span class="token punctuation">:</span> <span class="token string">'./login.css'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Login</span> <span class="token punctuation">{</span>

  userModel<span class="token punctuation">:</span> WritableSignal<span class="token operator">&lt;</span>IUser<span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    email<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    password<span class="token punctuation">:</span> <span class="token string">''</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">,</span> <span class="token punctuation">(</span>schema<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">email</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is not valid'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>password<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'password is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">onSubmit</span><span class="token punctuation">(</span>event<span class="token punctuation">:</span> Event<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">submit</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> u <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">userModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Logging in with:'</span><span class="token punctuation">,</span> u<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>In the template, the form can be created as shown below:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">(submit)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>onSubmit($event)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
        Email
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.email<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
    @if (loginForm.email().invalid() &amp;&amp; loginForm.email().touched()) {
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>error<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        @for (error of loginForm.email().errors(); track error.kind) {
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>{{ error.message }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        }
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    }

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
        Password
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.password<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
    @if (loginForm.password().invalid() &amp;&amp; loginForm.password().touched()) {
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>error<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        @for (error of loginForm.password().errors(); track error.kind) {
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>{{ error.message }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        }
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    }
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">[disabled]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm().invalid()<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Login<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
</code></pre><h3 id="understanding-forms-models">Understanding Forms Models</h3><p>Signal Forms are backed by a model, which is a writable signal. When the model value changes, the form updates automatically. Likewise, when the user interacts with the form, the model is updated. In this way, the model and the form are connected through two-way binding, which means changes in one are reflected in the other.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-06/model-signal-form.png?sfvrsn=a528e8f8_2" alt="Model and Signal Form exchange change updates" /></p><p>It is always best practice to use an interface to define the model. For example, if we are creating a form to edit a product, we can define a type for it as shown below.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IProduct</span><span class="token punctuation">{</span>
    id<span class="token punctuation">:</span><span class="token keyword">number</span><span class="token punctuation">;</span>
    name<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span>
    price<span class="token punctuation">:</span><span class="token keyword">number</span><span class="token punctuation">;</span>
    description<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span>
    category<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span> 
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IProductForm</span> <span class="token keyword">extends</span> <span class="token class-name">Omit</span><span class="token operator">&lt;</span>IProduct<span class="token punctuation">,</span> <span class="token string">'id'</span> <span class="token operator">|</span> <span class="token string">'category'</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre><p>Now to edit the product, fetch it from the API using the resource API as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">    idToFetch <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    productsResource <span class="token operator">=</span> <span class="token function">resource</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        params<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>idToFetch<span class="token punctuation">,</span>
        loader<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> params <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            <span class="token keyword">let</span> id <span class="token operator">=</span> params<span class="token punctuation">;</span>
            <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`http://localhost:3000/product/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>response<span class="token punctuation">.</span>ok<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`HTTP error! status: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>response<span class="token punctuation">.</span>status<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            <span class="token keyword">return</span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> Promise<span class="token operator">&lt;</span>IProductForm<span class="token operator">&gt;</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>We have received the product data to be updated from the API. In the next step, we will create a signal-based form to bind this data and allow the user to update the product.</p><pre class=" language-ts"><code class="prism  language-ts">   productUpdateModel <span class="token operator">=</span> signal<span class="token operator">&lt;</span>IProductForm<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        name<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
        price<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
        description<span class="token punctuation">:</span> <span class="token string">''</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    productForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>productUpdateModel<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>That&rsquo;s it. Now, in the template, use the <code>formField</code> directive to display the fetched product data in the form, as shown below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">(submit)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>onSubmit($event)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
        Name
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm.name<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
        Price
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>number<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm.price<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
        Description
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm.description<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">[disabled]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm().invalid()<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Update<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>To update the product, let&rsquo;s add an input field and a button to load the product.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>Update Product Id : &lt;input #productIdInput type="number" [value] ='idToFetch()'/&gt;<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>fetchProduct(+productIdInput.value)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Load Product<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>To fetch the updated product, set the signal accordingly. There are multiple ways to bind the value returned from the API to the <code>productUpdateModel</code>. You can either use <code>productResource.value()</code> directly in the template or assign it as shown below.</p><pre class=" language-ts"><code class="prism  language-ts">   <span class="token function">fetchProduct</span><span class="token punctuation">(</span>id<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>idToFetch<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>productsResource<span class="token punctuation">.</span><span class="token function">hasValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>productUpdateModel<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>productsResource<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
</code></pre><p>As you see from the above example, the form model and form fields are in two-way data-binding synchronisation, and changes flow bidirectionally between them.</p><p>The interaction between user input and the model follows these steps:</p><ol><li>The user enters text or selects a value from the dropdown.</li><li>The <code>formField</code> directive detects the change.</li><li>The corresponding <code>FieldState</code> is updated.</li><li>The model signal is updated accordingly.</li></ol><p>This flow is illustrated in the diagram below.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-06/user-input-model-interaction.png?sfvrsn=1c3ac370_2" alt="user inputs. formField directive detects the change. FieldState updated. Model signal updates" /></p><p>The flow between the model and the user input follows the steps below:</p><ol><li>Use code to <code>set()</code> or <code>update()</code> signal model</li><li>Notifies all subscribers</li><li>Field state updates</li><li><code>formField</code> directive updates the input element</li></ol><p>This flow is illustrated in the diagram below.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-06/set-update-signal-model.png?sfvrsn=19cf05a3_2" alt="set() or update() signal model. Notifies all subscribers. Field state updates. formField directive updates input element." /></p><p>Two-way data synchronization can be better understood by the following simple code example.</p><pre class=" language-ts"><code class="prism  language-ts">count <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">{</span> v<span class="token punctuation">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  countInput <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>count<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">updateCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>count<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span>c <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> v<span class="token punctuation">:</span> c<span class="token punctuation">.</span>v <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre><p>And on the template:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>number<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>countInput.v<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>updateCount()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>update count<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Count: {{ count().v }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>When you run the above code, you will see that the input and model value are in sync with each other.</p><h2 id="optional-fields">Optional Fields</h2><p>Always use explicit TypeScript type to define the model. So to create a login form create a type like below.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IUser</span> <span class="token punctuation">{</span>
    email<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span> 
    password <span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span> 
    rememeberme<span class="token operator">?</span><span class="token punctuation">:</span> <span class="token keyword">boolean</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>You use them to create a signal form as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">  userModel<span class="token punctuation">:</span> WritableSignal<span class="token operator">&lt;</span>IUser<span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    email<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    password<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    rememberMe<span class="token punctuation">:</span> <span class="token keyword">null</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>When you define a form using explicit types as shown above, the resulting field tree is fully type-safe. For example, <code>loginForm.email</code> is inferred as <code>FieldTree&lt;string&gt;</code>, and any attempt to access a property that doesn&rsquo;t exist will produce a compile-time error. In the code below, TypeScript will infer type of email as string.</p><pre class=" language-ts"><code class="prism  language-ts">email <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span>email<span class="token punctuation">;</span>
</code></pre><p>And to set the optional field:</p><ul><li>Set the value explicitly to null</li><li>For input fields such <code>&lt;input type=&rdquo;text&rdquo; /&gt;</code>, set the value to empty string.</li><li>Do not use undefined</li></ul><p>Fields explicitly set to undefined are omitted from the field tree. A model defined as <code>{ value: undefined }</code> behaves the same as <code>{}</code>. Accessing that field returns undefined instead of a <code>FieldTree</code> instance.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-06/optional-fields.png?sfvrsn=916d9551_2" alt="Optional fields. Use null for optional fields. Do not use undefined, as it won’t be part of FieldTree." /></p><h2 id="nested-objects-in-model">Nested Objects in Model</h2><p>You can use nested objects to create a form like below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IProduct</span> <span class="token punctuation">{</span>
    id<span class="token punctuation">:</span><span class="token keyword">number</span><span class="token punctuation">;</span>
    name<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span>
    price<span class="token punctuation">:</span><span class="token keyword">number</span><span class="token punctuation">;</span>
    description<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span>
    category<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span>
    vendor <span class="token punctuation">:</span> IVendor<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IVendor</span><span class="token punctuation">{</span>
    id<span class="token punctuation">:</span><span class="token keyword">number</span><span class="token punctuation">;</span>
    name<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span>
    email<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span>
    phone<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span>   
<span class="token punctuation">}</span>
</code></pre><p>Next, you can create the form using the nested object as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">   productModel <span class="token operator">=</span> signal<span class="token operator">&lt;</span>IProduct<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    id<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
    name<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    price<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
    description<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    category<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>  
    vendor<span class="token punctuation">:</span> <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
      name<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
      email<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
      phone<span class="token punctuation">:</span> <span class="token string">''</span>
    <span class="token punctuation">}</span> 
   <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

   productForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>productModel<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In the template, you can access nested object properties using dot notation, as shown below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">(submit)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>onSubmit($event)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>Name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm.name<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>Vendor Name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm.vendor.name<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Submit<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Before moving to the validation section, note that the form model and the domain model are two different concepts and should be treated separately.</p><p>Your API response may map directly to the domain model, but you should define a dedicated form model when working with signal-based forms.</p><p>We will explore this distinction in more detail in a separate article.</p><h2 id="validations">Validations</h2><p>You pass validation rules to the Signal Forms using a schema. You pass schema as second parameter to the form function.</p><pre class=" language-ts"><code class="prism  language-ts">  userModel<span class="token punctuation">:</span> WritableSignal<span class="token operator">&lt;</span>IUser<span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    email<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    password<span class="token punctuation">:</span> <span class="token string">''</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


  loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">,</span> <span class="token punctuation">(</span>schema<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">email</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is not valid'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>password<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'password is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>As shown above, you provide a schema definition along with validation rules to apply validations to the respective fields of the form.</p><p>The schema function gets a <code>SchemaPathTree</code> object that lets us define the validation rules. The schema function runs at the time of initialization, and validation runs automatically whenever field values change.</p><p>On the template, you can use the validation as shown below:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
        Email
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.email<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
    @if (loginForm.email().invalid() &amp;&amp; loginForm.email().touched()) {
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>error<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        @for (error of loginForm.email().errors(); track error.kind) {
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>{{ error.message }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        }
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    }
</code></pre><p>Validation works in these steps:</p><ol><li>Define validation rules in schema</li><li>Validation rules runs when filed value changes</li><li>Validation errors are propagated as signals</li><li>UI automatically updates when validation state changes</li></ol><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-06/define-validation-rules-flow.png?sfvrsn=d710c039_2" alt="Define validation rules. Automatic execution of validation rules. Validation error propagates as Signals. Reactive update of UI on validation state changes" /></p><p>There are two types of validations:</p><ol><li>Synchronous validation &ndash; <code>required()</code>, <code>email()</code>, etc.</li><li>Asynchronous validation &ndash; <code>validateHttp()</code></li></ol><p>When a field value changes, Angular runs validation in the sequence:</p><ol><li>First it runs all synchronous validations.</li><li>If all synchronous validation pass, then it runs asynchronous validation.</li><li>After that, it updates the field state signal values such as <code>valid()</code>, <code>invalid()</code>, <code>errors()</code> and <code>pending()</code>.</li></ol><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-06/sync-validations-flow.png?sfvrsn=d7f77ce4_2" alt="Flow chart. Run synchronous validations. Passed – no or Run async validation. Update field state." /></p><p>Angular provides these built-in validation rules:</p><ol><li><code>required()</code></li><li><code>email()</code></li><li><code>min()</code></li><li><code>max()</code></li><li><code>minLength()</code></li><li><code>maxLength()</code></li><li><code>pattern()</code></li></ol><p>You can apply <code>required()</code> and <code>email()</code> validation on email field as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">  loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">,</span> <span class="token punctuation">(</span>schema<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">email</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is not valid'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>When you have multiple validation rules applied, each rule runs independently and can cause form to be invalid.</p><p>Angular Signal Forms make it straightforward to implement custom validations. For example, if you want to verify that the email belongs to the nomadcoder domain, you can easily add a custom validator as shown below.</p><pre class=" language-ts"><code class="prism  language-ts">  loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">,</span> <span class="token punctuation">(</span>schema<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">email</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is not valid'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token function">validate</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> value <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">endsWith</span><span class="token punctuation">(</span><span class="token string">'@nomadcoder.ai'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token punctuation">{</span>
          kind<span class="token punctuation">:</span> <span class="token string">'emailDomain'</span><span class="token punctuation">,</span>
          message<span class="token punctuation">:</span> <span class="token string">'Email must end with @nomadcoder.ai'</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In upcoming articles, we will get into details of custom validation and asynchronous validation.</p><h2 id="form-field-and-its-signal-properties">Form Field and Its Signal Properties</h2><p>The <code>form</code> function returns a <code>FieldTree</code> that represents all properties of the model. Each property is exposed as a signal, and each property signal includes a set of attributes that are also implemented as signals.</p><p>When you access a field from the field tree, as shown below, you can retrieve its associated attributes as illustrated:</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-06/field-tree-attributes.png?sfvrsn=d73e4df6_2" alt="After  the next line has  and a list of attributes comes up" /></p><p>The various signal attributes are as below:</p><ol><li><code>value()</code></li><li><code>dirty()</code></li><li><code>hidden()</code></li><li><code>errors</code></li><li><code>errorSummary</code></li><li><code>valid</code></li><li><code>invalid</code></li><li><code>pending</code></li><li><code>submitting</code></li><li>Etc.</li></ol><p>As all these are <code>signals()</code>, they can be directly used on the template. I hope now you understand Angular Signal Forms. In coming articles, we will go deeper into:</p><ol><li><a href="https://www.telerik.com/blogs/async-validation-angular-signal-forms" target="_blank">asynchronous validators</a></li><li>custom validators</li></ol><p>I hope you find this article useful. Thanks for reading.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Angular Signals: Building a Reactive Countdown Timer</h4></div><div class="col-8"><p class="u-fs16 u-mb0">A comprehensive tutorial for experienced Angular developers to learn <a target="_blank" href="https://www.telerik.com/blogs/angular-signals-building-reactive-countdown-timer">Angular Signals by building a practical countdown timer</a> application with computed signals and effects.</p></div></div></aside><img src="https://feeds.telerik.com/link/23055/17374360.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:3f695ccd-2fff-4d8d-af98-598fe8161769</id>
    <title type="text">Building Component-Aware Production UIs with Angular and Kendo UI MCP</title>
    <summary type="text">Through MCP, we can use component-aware AI to help us build user interfaces in conjunction with our favorite component libraries. See it in Angular!</summary>
    <published>2026-06-15T16:26:20Z</published>
    <updated>2026-09-02T08:08:54Z</updated>
    <author>
      <name>Dany Paredes </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17361560/building-component-aware-production-ui-angular-kendo-ui-mcp"/>
    <content type="text"><![CDATA[<p><span class="featured">Through MCP, we can use component-aware AI to help us build user interfaces in conjunction with our favorite component libraries. See it in Angular!</span></p><p>We as developers use AI tools like Cursor, Claude Code and Copilot; they have changed how we write code. We delegate entire sections of our applications to an agent, and for many tasks, this works really well.</p><p>But when it comes to building user interfaces with a specific framework, things get complicated fast. Results are unpredictable, the code feels incomplete and we end up spending more time fixing than building.</p><p>If you have felt that, you are not alone. The good news is that the problem is not the AI. The problem is how we are using it.</p><p>We will see why AI struggles with UI development and how a new approach called &ldquo;component-aware AI&rdquo; changes everything. But first, let&rsquo;s understand what is really missing.</p><h2 id="the-problem">The Problem</h2><p>In the world of AI, we read about context all the time, which is the key problem when things go wrong. When you ask your AI assistant to use a component from a specific framework, it relies on its training data. It does not know:</p><ul><li>The exact version of Angular you are using</li><li>The best practices for your library</li><li>The specific design rules of your organization</li></ul><blockquote><p>Do you want to learn more about the <a href="https://www.progress.com/resources/webinars/the-context-problem-behind-stalled-ai-roi">context problem</a>?</p></blockquote><p>So the AI starts guessing. And that guessing creates real problems:</p><ul><li><strong>High costs and effort:</strong> We waste many tokens just explaining our UI library to the AI. We end up copying and pasting manuals, providing code examples and fixing mistakes, making the whole process slow and expensive.</li><li><strong>The &ldquo;fix and repeat&rdquo; loop:</strong> We copy the code, find a small bug, ask the AI to fix it and repeat the cycle.</li><li><strong>Low-quality code:</strong> The code the AI gives us is often incomplete or outdated. We spend more time fixing it than it would have taken to write it from scratch.</li></ul><p>But we have good news: using a new approach called &ldquo;component-aware AI&rdquo; changes everything.</p><h2 id="the-shift-to-mcp">The Shift to MCP</h2><p>We need a new way for the AI to work. We need &ldquo;component-aware AI.&rdquo; This shift is made possible by the <a href="https://www.telerik.com/blogs/promise-model-context-protocol">Model Context Protocol (MCP)</a>. Instead of the AI trying to remember code from its training data, it can read the live documentation of your library in real time.</p><p>Think of it like the difference between following a recipe from memory versus using a smart kitchen robot with everything preconfigured. It is automated, precise and much freer from errors.</p><p>When you use an MCP like the Progress Kendo UI for <a href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/agentic-ui-generator/getting-started">Angular MCP</a>, the AI assistant queries the official library data before it writes any code. This verifies that every property and every method is correct.</p><p>The best way to understand the difference is to see it in action. I have experienced the shift from working with blind AI to giving agents the right tools to deliver code with confidence and without technical debt. Let&rsquo;s do it!</p><blockquote><p>Want to build your own MCP server? Check this out: <a href="https://www.youtube.com/watch?v=mM8T8bSCTyk">https://www.youtube.com/watch?v=mM8T8bSCTyk</a></p></blockquote><h2 id="the-traditional-way-the-blind-ai">The Traditional Way (The &ldquo;Blind&rdquo; AI)</h2><p>Let&rsquo;s start with the scenario you probably already know.</p><p>Open your terminal and run these two commands to create the project and install the Kendo UI for <a href="https://www.telerik.com/kendo-angular-ui/components/grid">Angular Grid</a>:</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token comment"># Create the project</span>
ng new accounting-app --style<span class="token operator">=</span>scss --ssr<span class="token operator">=</span>false
 
<span class="token comment"># Install Kendo UI Grid</span>
ng add @progress/kendo-angular-grid
</code></pre><p>Then, you ask your AI assistant (without specialized context) to build the interface:</p><blockquote><p><strong>Prompt:</strong> &ldquo;Create a General Ledger grid with Kendo UI for Angular. Show Date, Description, Debit, and Credit. Add footer totals.&rdquo;</p></blockquote><p>The project compiles and runs, but the result is full of immediate technical debt. Here is what the AI generates:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token comment">// ❌ BLIND AI: Ignores Kendo built-in aggregation utilities</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token punctuation">{</span>
 <span class="token keyword">protected</span> readonly ledgerItems<span class="token punctuation">:</span> LedgerEntry<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
 
 <span class="token comment">// Manual logic the developer must maintain forever</span>
 <span class="token keyword">protected</span> <span class="token keyword">get</span> <span class="token function">totalDebit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">number</span> <span class="token punctuation">{</span>
   <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>ledgerItems<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span>sum<span class="token punctuation">,</span> item<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> sum <span class="token operator">+</span> item<span class="token punctuation">.</span>debit<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">}</span>
 
 <span class="token keyword">protected</span> <span class="token keyword">get</span> <span class="token function">totalCredit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">number</span> <span class="token punctuation">{</span>
   <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>ledgerItems<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span>sum<span class="token punctuation">,</span> item<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> sum <span class="token operator">+</span> item<span class="token punctuation">.</span>credit<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Let&rsquo;s look at the problems here. For <code>totalDebit</code>, if you add more columns with totals, you have to manually write a <code>.reduce()</code> for each one. The AI does not know that Kendo UI already has <a href="https://www.telerik.com/kendo-angular-ui/components/grid/grouping/aggregates"><code>aggregateBy</code></a> built in.</p><p>Another common inconsistency is with colors. Instead of using design tokens, it uses hard-coded values like <code>#f5f7fb</code>, which breaks visual coherence across the app.</p><p>The worst part is the lack of accessibility. There are no ARIA attributes or semantic roles, which Kendo UI handles automatically when configured correctly.</p><pre class=" language-html"><code class="prism  language-html"><span class="token comment">&lt;!-- ❌ BLIND AI: Hardcoded color, no accessibility, no built-in features --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>kendo-grid</span> <span class="token attr-name">[data]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ledgerItems<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>kendo-grid-column</span> <span class="token attr-name">color</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#f5f7fb<span class="token punctuation">"</span></span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>debit<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Debit<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>kendo-grid-column</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>kendo-grid</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>In the end, you spend more time cleaning up AI code than you would have spent writing it from scratch. The real issue is that we are not giving the AI the right tools to perform at its best.</p><p>We can fix that, because the solution is simpler than you might think.</p><h2 id="the-agentic-way-using-the-power-of-kendo-ui-mcp">The Agentic Way: Using the Power of Kendo UI MCP</h2><p>Now, let&rsquo;s move to the productive workflow and combine the power of Kendo UI MCP with our agents.</p><p>Instead of the manual configuration and the &ldquo;blind&rdquo; approach, we start with a single command. Open your terminal and run:</p><pre class=" language-bash"><code class="prism  language-bash">npx kendo angular setup
</code></pre><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-06/npx-kendo-angular-set.png?sfvrsn=58d383f_2" alt="Git npx kendo angular setup" /></p><p>Here is where the magic happens. It automatically installs the license and registers the <strong>Kendo UI MCP Server</strong> across your IDEs and AI agents (VS Code, Cursor, Claude Code). From this point on, your agent has full context and no longer has to guess.</p><p>Now we ask the same AI agent to build the same application with the same prompt. This time our agent, thanks to MCP, uses the <code>Kendo UI Generator</code> tool to generate the code.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-06/angular-mcp-grid.png?sfvrsn=8457b8db_2" alt="Create a general ledger grid with Kendo UI for Angular. Show date, description, debit, and credit. Add footer totals." /></p><p>Let&rsquo;s look at the generated code and why it is production-ready.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token comment">// ✅ COMPONENT-AWARE AI: Uses Signals, Modern Angular Patterns, and Kendo's aggregateBy</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> aggregateBy<span class="token punctuation">,</span> AggregateResult <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-data-query'</span><span class="token punctuation">;</span>
 
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">GeneralLedgerComponent</span> <span class="token punctuation">{</span>
 <span class="token keyword">private</span> ledgerService <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>LedgerService<span class="token punctuation">)</span><span class="token punctuation">;</span>
 
 <span class="token comment">// Modern signal-based state</span>
 <span class="token keyword">protected</span> ledgerEntries <span class="token operator">=</span> signal<span class="token operator">&lt;</span>LedgerEntry<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>ledgerService<span class="token punctuation">.</span><span class="token function">getLedgerEntries</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 
 <span class="token comment">// Kendo's aggregateBy handles all column totals in one call, no manual .reduce() needed</span>
 <span class="token keyword">protected</span> totals <span class="token operator">=</span> computed<span class="token operator">&lt;</span>AggregateResult<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
   <span class="token function">aggregateBy</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">ledgerEntries</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>
     <span class="token punctuation">{</span> field<span class="token punctuation">:</span> <span class="token string">'debit'</span><span class="token punctuation">,</span> aggregate<span class="token punctuation">:</span> <span class="token string">'sum'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
     <span class="token punctuation">{</span> field<span class="token punctuation">:</span> <span class="token string">'credit'</span><span class="token punctuation">,</span> aggregate<span class="token punctuation">:</span> <span class="token string">'sum'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
   <span class="token punctuation">]</span><span class="token punctuation">)</span>
 <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>The AI now uses Signals (<code>signal</code>, <code>computed</code>) and proper dependency injection (<code>inject</code>), which are the recommended modern Angular patterns. And instead of a manual <code>.reduce()</code> per column, it uses Kendo UI <code>aggregateBy</code>. Add a new column with a total, and you just add one line to the array, nothing else.</p><p>In the SCSS file, instead of hard-coding colors, it uses official Kendo UI Design Tokens such as <code>var(--kendo-color-surface-alt)</code> and <code>var(--kendo-color-success)</code>.</p><p>And in the template, the difference is clear:</p><pre class=" language-html"><code class="prism  language-html"><span class="token comment">&lt;!-- ✅ COMPONENT-AWARE AI: Design tokens, accessibility, full features enabled --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>kendo-grid</span>
   <span class="token attr-name">[data]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ledgerEntries()<span class="token punctuation">"</span></span>
   <span class="token attr-name">[reorderable]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span>
   <span class="token attr-name">[navigable]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span>
   <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>table<span class="token punctuation">"</span></span>
   <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>General Ledger Entries<span class="token punctuation">"</span></span>
<span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>kendo-grid</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>That is the key difference. When we use <a href="https://www.telerik.com/kendo-angular-ui/components/ai-tools">Kendo UI for Angular MCP</a>, our agents do not just generate code. They generate the right code, follow best practices and deliver to a high standard.</p><p>Here are the three benefits I value most:</p><ol><li>Significantly reduced hallucinations: The AI does not guess property names. It reads the actual documentation in real time.</li><li>Accessible by default: Kendo UI components are built to follow accessibility standards. When the AI uses these components correctly, your app is automatically inclusive.</li><li>Token efficiency: No more copying large lines of documentation into your chat. The AI fetches only what it needs, saving you tokens and money.</li></ol><blockquote><p>Go deeper and explore <a href="https://www.telerik.com/kendo-angular-ui/components/ai-tools#kendo-ui-for-angular-ai-tools-overview">everything that Kendo UI MCP can do</a>.</p></blockquote><p>Now that we have seen both worlds side by side, let&rsquo;s talk about what this really means for how we choose our tools going forward.</p><h2 id="conclusion">Conclusion</h2><p>Simply using AI is not enough. And simply using a component library is not enough anymore, either.</p><p>This is the paradigm shift. We are moving from a world where a library just gives you components to one where a library also provides the context layer that makes modern development possible. Kendo UI MCP is exactly that: it acts as a bridge between your agents and the library so that the AI can do its job properly rather than guessing.</p><p>By bridging that context gap, we move from &ldquo;guessing&rdquo; to &ldquo;knowing&rdquo; and agents stop hallucinating APIs and start delivering production-ready code.</p><blockquote><p>My personal take: Next time you evaluate a UI library, do not just look at the component catalog. Ask if your framework has the tools for the way we build software today. Because that is the question I ask myself now, every time.</p></blockquote><blockquote><p>BTW, if you want to work less and ship more, it is time to <a href="https://www.telerik.com/blogs/angular-kendo-ui-mcp-making-agents-work">make your agents work for you</a> so you can focus on building what really matters.</p></blockquote><h3 id="resources">Resources</h3><ul><li><a href="https://www.telerik.com/kendo-angular-ui"><strong>Kendo UI for Angular</strong></a></li><li><strong>MCP Protocol:</strong> <a href="https://modelcontextprotocol.io/">Learn more about MCP</a></li></ul><h2 id="try-now">Try Now</h2><p>Remember, Kendo UI for Angular comes with a free 30-day trial, so you can explore all these goodies yourself.</p><p><a href="https://www.telerik.com/try/kendo-angular-ui" class="Btn">Try Now</a></p><img src="https://feeds.telerik.com/link/23055/17361560.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:288b4cc6-8c92-4dec-a932-bed600474298</id>
    <title type="text">Angular 22: The Evolution of Modern Angular</title>
    <summary type="text">Signals, OnPush, declarative async resources: Angular 22 makes standard several features that help developers build better apps.</summary>
    <published>2026-06-05T21:01:27Z</published>
    <updated>2026-09-02T08:08:54Z</updated>
    <author>
      <name>Dany Paredes </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17354974/angular-22-evolution-modern-angular"/>
    <content type="text"><![CDATA[<p><span class="featured">Signals, OnPush, declarative async resources: Angular 22 makes standard several features that help developers build better apps.</span></p><p>A few days ago, we checked out <a target="_blank" href="https://www.telerik.com/blogs/google-io-2026-developers-moving-ai-agentic-era">Google I/O 2026</a>, and today we need to talk about our favorite framework: <strong>Angular</strong>. Why? Because <strong>version 22</strong> is here!</p><p>Angular v22 is a major update focused on stability, performance and ergonomic APIs. It brings a more polished signal-driven platform and better data loading primitives that make modern apps feel faster and simpler to build.</p><p>Before we look at the most interesting changes, let&rsquo;s talk about the foundation. Angular v22 stabilizes the features we have been testing in the last few versions. If you want to build a high-performance app today, these are the new standards.</p><h2 id="stable-signal-forms-and-httpresource">Stable Signal Forms and httpResource</h2><p>Reactive Forms were great, but they often felt separate from the modern Signal-based reactivity. In v22, <strong>Signal Forms are officially stable</strong>.</p><p>What does this mean for us?</p><ul><li><strong>Better reactivity:</strong> No more unnecessary updates when a single field changes.</li><li><strong>Better type safety:</strong> We finally have a form system that works perfectly with TypeScript.</li></ul><p>Do you remember <code>HttpClient</code> and the manual <code>toSignal</code> conversions? They worked, but they added extra code. Now we have <code>httpResource</code>.</p><p>It is the new standard for fetching data. It treats your HTTP requests as signals, automatically handling the loading, error, and data states for you.</p><blockquote><p><strong>Learn more:</strong> Dive deeper into <a target="_blank" href="https://www.telerik.com/blogs/getting-started-httpresource-api-angular">Getting Started with httpResource API</a> and learn more about <a target="_blank" href="https://www.telerik.com/blogs/angular-signal-forms-vs-reactive-forms">Angular Signal Forms vs. Reactive Forms</a>.</p></blockquote><p>But what if your request depends on another signal? In v22, we have the new <code>chain()</code> method. It allows you to link resources together. If the first resource is loading, the second one waits automatically. This is a big win for complex data!</p><p><strong>Wait, what if you are already using RxJS?</strong> Don&rsquo;t worry, Angular has a solution for that too. Let&rsquo;s see how v22 handles the transition from Observables to Resources.</p><h2 id="rxresource-vs.-httpresource">RxResource vs. httpResource</h2><p>A common question is: &ldquo;Should I stop using RxJS?&rdquo; The answer is <strong>no</strong>. Angular v22 introduces <code>rxResource</code> as the perfect partner for your existing Observable streams.</p><ul><li><strong><code>httpResource</code></strong>: Use this for standard API calls. It is optimized for the Fetch API and handles JSON automatically.</li><li><strong><code>rxResource</code></strong>: Use this when your data source is an existing Observable. It allows you to use the power of RxJS operators inside the clean, Signal-based Resource API.</li></ul><p>Now that we have our data fetching ready, how do we make sure our users and agents can navigate efficiently? Let&rsquo;s talk about the new smart navigation features in the Router.</p><h2 id="smart-navigation-and-incremental-hydration">Smart Navigation and Incremental Hydration</h2><p>The Angular Router received some updates in v22 that solve common problems.</p><ul><li><strong>URL decoupling:</strong> You can now keep a clean URL in the address bar while the app shows a different state. With the new <code>browserUrl</code> input on <code>RouterLink</code>, you can show <code>/settings</code> while the router actually uses <code>/</code><code>account/advanced-preferences</code>.</li><li><strong>Parameter inheritance:</strong> Child routes now inherit parameters from their parents by default, and you don&rsquo;t need extra configuration to get an ID from a parent route.</li></ul><p>But a great UI and smart routing mean nothing if the page is slow to load. This brings us to the most impressive performance update in v22: <strong>incremental hydration</strong>.</p><p>Server-Side Rendering (SSR) is no longer a problem. In v22, <strong>incremental hydration is the default</strong>.</p><p>Angular now loads your application in small parts as they become visible. Combined with <strong>resource caching</strong>, the client can use the data fetched on the server without making a second API call. The user sees the data instantly, and the &ldquo;flicker&rdquo; of reloading data is gone.</p><blockquote><p><strong>Learn more:</strong> Explore <a target="_blank" href="https://www.telerik.com/blogs/new-angular-hydration">The New Angular Hydration</a> for in-depth details.</p></blockquote><p>But performance is also about how the browser handles changes. This is where the biggest change in Angular&rsquo;s history reaches its peak.</p><h2 id="onpush-by-default">OnPush by Default</h2><p>For years, <code>ChangeDetectionStrategy.Eager</code> (previously known as `Default`) was the standard for Angular&rsquo;s change detection. With v22, <code>ChangeDetectionStrategy.OnPush</code>is now the default for new components!</p><p>By using <code>ChangeDetectionStrategy.OnPush</code> as the default, we get:
</p><ul><li><strong>Better performance:</strong> The framework only checks what it needs to, exactly when it needs to, avoiding unnecessary checks.</li><li><strong>A step closer to Zoneless:</strong> This sets the stage for eventually dropping <code>zone.js</code> in the future.</li></ul><p>If you have an older app, don&rsquo;t worry! There is a migration tool that adds <code>ChangeDetectionStrategy.Eager</code> (the new name for the old behavior) to your existing components exactly as before.</p><p>Now, how do we make sure our fast code actually works? Let&rsquo;s talk about the new speed king of testing.</p><h2 id="vitest">Vitest</h2><p>Testing used to be the slow part of our work. Not anymore. Angular v22 officially replaces Karma/Jasmine with <strong>Vitest</strong> as the default test runner.</p><p>It is very fast and shares the same configuration as your build pipeline. Also, the new <code>migrate-karma-to-vitest</code> tool makes the change very easy, even for complex tests!</p><blockquote><p>Do you want to try <a target="_blank" href="https://www.telerik.com/blogs/unit-testing-angular-modern-testing-vitest">Vitest</a>?</p></blockquote><h2 id="angular-aria-accessibility-for-everyone">Angular Aria: Accessibility for Everyone</h2><p>Building custom components with correct ARIA roles and focus management can be difficult. In v22, <strong>Angular Aria is officially stable</strong>.</p><p>Think of it as <strong>&ldquo;headless accessibility.&rdquo;</strong> It provides the logic you need to build your own accessible components. It handles the complicated parts of ARIA attributes and keyboard interactions for you.</p><p>Why does this matter for AI? Because accessible apps are much easier for AI Agents to understand!</p><blockquote><p>Check this example about <a target="_blank" href="https://www.telerik.com/blogs/build-accessible-components-angular-aria">how to build accessible components with Angular Aria</a>.</p></blockquote><h2 id="async-dependency-injection">Async Dependency Injection</h2><p>The <code>injectAsync()</code> function allows us to lazy-load services only when they are actually needed, while still creating the instance with Angular dependency injection. This keeps your app small and fast.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">CheckoutComponent</span> <span class="token punctuation">{</span>
  <span class="token comment">// We declare the lazy injection in the injection context (class field)</span>
  <span class="token keyword">private</span> paymentGatewayLoader <span class="token operator">=</span> <span class="token function">injectAsync</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> 
    <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">'./payment-gateway.service'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>m <span class="token operator">=&gt;</span> m<span class="token punctuation">.</span>PaymentGatewayService<span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">async</span> <span class="token function">onCheckoutCompleted</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// We only load the heavy PaymentGatewayService when the user actually checks out!</span>
    <span class="token keyword">const</span> paymentGateway <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">paymentGatewayLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">await</span> paymentGateway<span class="token punctuation">.</span><span class="token function">processTransaction</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><h2 id="building-a-dashboard-with-angular-22">Building a Dashboard with Angular 22</h2><p>Instead of just explaining features, let&rsquo;s build a practical dashboard example that uses the stable core of Angular v22: <code>@Service()</code>, <code>httpResource()</code> and the new template syntax.</p><blockquote><p><strong>Want to follow along?</strong> You can clone the complete project from GitHub: <a target="_blank" href="https://github.com/danywalls/angular-22-nba-finals">angular-22-nba-finals</a>. Just run <code>npm start</code> and you&rsquo;ll have the dashboard running locally.</p></blockquote><h3 id="the-data-service-with-service">The Data Service with @Service</h3><p>Now, let&rsquo;s create our service. We will use the new <code>@Service()</code> decorator (which replaces <code>@Injectable()</code>) and <code>httpResource</code> to fetch the games. Notice how <code>httpResource</code> handles loading and error states for you.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token comment">// src/app/nba.service.ts</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Service <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> httpResource <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/common/http'</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">NbaGame</span> <span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
  gameNumber<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
  homeTeam<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
  homeScore<span class="token punctuation">:</span> <span class="token keyword">number</span> <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
  awayTeam<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
  awayScore<span class="token punctuation">:</span> <span class="token keyword">number</span> <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
  status<span class="token punctuation">:</span> <span class="token string">'Final'</span> <span class="token operator">|</span> <span class="token string">'Scheduled'</span><span class="token punctuation">;</span>
  date<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
  location<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

@<span class="token function">Service</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">NbaService</span> <span class="token punctuation">{</span>
  <span class="token comment">// httpResource is the standard for fetching data</span>
  gamesResource <span class="token operator">=</span> httpResource<span class="token operator">&lt;</span>NbaGame<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token string">'/api/nba-finals'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><h3 id="the-ui-layer--error-states">The UI Layer &amp; Error States</h3><p>We display the data using the new <code>@for</code> block and keep the error handling inside the component template. This keeps the example focused on stable Angular v22 behavior.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token comment">// src/app/app.ts</span>
@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  template<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`
    &lt;app-dashboard&gt;&lt;/app-dashboard&gt;
    &lt;router-outlet&gt;&lt;/router-outlet&gt;
  `</span></span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre><p>Our Dashboard component remains simple:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token comment">// src/app/dashboard.component.ts</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Component<span class="token punctuation">,</span> inject <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> NbaService <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./nba.service'</span><span class="token punctuation">;</span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-dashboard'</span><span class="token punctuation">,</span>
  template<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`
    &lt;div class="dashboard"&gt;
      &lt;h1&gt;NBA Finals 2026: Knicks vs Spurs&lt;/h1&gt;

      @if (nbaService.gamesResource.isLoading()) {
         &lt;p&gt;Loading game data...&lt;/p&gt;
      } @else {
        &lt;div class="cards"&gt;
          @for (game of nbaService.gamesResource.value(); track game.id) {
            &lt;div class="card"&gt;
              &lt;div class="meta"&gt;Game {{ game.gameNumber }} &bull; {{ game.date }}&lt;/div&gt;
              &lt;div class="score"&gt;
                {{ game.homeTeam }} {{ game.homeScore }} vs {{ game.awayScore }} {{ game.awayTeam }}
              &lt;/div&gt;
              &lt;div class="status"&gt;{{ game.status }}&lt;/div&gt;
            &lt;/div&gt;
          }
        &lt;/div&gt;
      }
    &lt;/div&gt;
  `</span></span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">DashboardComponent</span> <span class="token punctuation">{</span>
  nbaService <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>NbaService<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Save changes and run <code>ng server</code> navigate in the browser and tada!!!</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-06/angular-22-signals-dashboard.png?sfvrsn=5aeda1c4_2" alt="Angular 22 example dashboard using signals and httpResource" /></p><p>Done!! We play with the stable part of Angular v22 using <code>@Service()</code> for a clean singleton service definition, <code>httpResource()</code> for declarative, signal-based HTTP loading and <code>@for</code> with <code>@if</code> in templates to render loading and data states.</p><p>And, of course, AI is not forgotten by the Angular team. They updated and added new tools for Angular MCP and Skills. Let&rsquo;s see them!</p><h2 id="angular-mcp-and-skills">Angular MCP and Skills</h2><p>Of course, Angular continues embracing AI. The Angular MCP exposes app state and builds workflows for tools that understand Angular projects. That includes server-side MCP tools such as <code>devserver.wait_for_build</code>, <code>devserver.start</code> and <code>devserver.stop</code>.</p><p>Version 22 also introduces Agent Skills for Angular, a lightweight set of skill definitions that give AI assistants direct knowledge of modern Angular idioms and best practices. These skills are useful for teams that want to integrate agent-assisted coding into their workflow without pain.</p><ul><li>Learn more about Angular MCP: <a target="_blank" href="https://angular.dev/ai/mcp">angular.dev/ai/mcp</a></li><li>Learn more about Agent Skills for Angular: <a target="_blank" href="https://github.com/angular/skills">github.com/angular/skills</a></li></ul><h2 id="recap">Recap</h2><p>Angular 22 is a declaration that the way we build for the web has evolved. And by using <strong>Signals</strong>, <strong>OnPush performance</strong> and <strong>declarative async resources</strong>, we can build applications that are faster, simpler and easier to maintain.</p><p>This release is about making stable patterns:</p><ul><li>Use <code>httpResource()</code> for fetch-heavy components.</li><li>Use <code>@Service()</code> for singleton services.</li><li>Use <code>injectAsync()</code> when you want to defer heavy service loading.</li><li>Let template syntax like <code>@for</code> and <code>@if</code> keep your view code readable.</li><li>Embrace the AI era with Agent Skills and MCP tools.</li></ul><p>My advice is don&rsquo;t just read this article&mdash;build something! Take the dashboard we sketched and turn it into an interactive experience with Progress <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/ai-chat">Kendo UI for Angular AI Chat</a>. A chat interface is a powerful way to explore the series score in real time and it&rsquo;s a great way to test Angular 22 with a modern Kendo UI scenario.</p><p>Feel free to <a target="_blank" href="https://youtu.be/h5OJUSS_8IA?is=WBc_bZuuQnx9b0EY">watch for all the new features in Angular 22</a>:</p><div data-sf-ec-immutable="" class="-sf-relative" contenteditable="false" style="width:560px;height:315px;"><div data-sf-disable-link-event=""><iframe width="560" height="315" src="https://www.youtube.com/embed/h5OJUSS_8IA?si=0Nzrxxm5BbAjRJz6" title="What’s new in Angular v22" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"></iframe></div></div><p>&nbsp;</p><p>For a complete overview and to verify all the new features, you can check the official release post: <a href="https://blog.angular.dev/announcing-angular-v22-c52bb83a4664" target="_blank">Announcing Angular v22</a>.</p><p><strong>Happy coding!</strong></p><img src="https://feeds.telerik.com/link/23055/17354974.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:00f2f87e-a41a-4c28-8ad3-079bcbc8bc0a</id>
    <title type="text">Angular Grid at Scale: How Kendo UI Handles Millions of Rows</title>
    <summary type="text">Angular Grid at Scale: How Kendo UI Handles Millions of Rows.</summary>
    <published>2026-04-21T16:17:26Z</published>
    <updated>2026-09-02T08:08:54Z</updated>
    <author>
      <name>Dany Paredes </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17323038/angular-grid-scale-how-kendo-ui-handles-millions-rows"/>
    <content type="text"><![CDATA[<p>Let&rsquo;s say the Monday after the Super Bowl, your boss wants to see a dashboard list of the more than 120 million people who watched it. (The reality of this situation does not matter. Just go with it!) Your boss says, &ldquo;The dashboard needs to show every connected viewer in real time. A grid. Sortable. Filterable. And it can&rsquo;t be slow.&rdquo;</p><p>You open your code editor, create an HTML table, and try to render one million rows. The browser freezes. The tab crashes. Your Monday just got worse.</p><p>You need to display large amounts of data in a grid without killing the browser. The trick is simple: don&rsquo;t render what the user can&rsquo;t see.</p><p>This is where <strong>virtual scrolling</strong> comes in. Instead of creating a DOM element for every single row, you only render the rows visible on screen, plus a few extra. The user scrolls smoothly through millions of records, each new batch loading in as needed, and the browser stays fast and responsive.</p><p>Let&rsquo;s do it together! Today, we will build a Super Bowl Dashboard in Angular. We will see how to handle one million viewers using Progress Kendo UI for <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/grid/">Angular Grid</a>. We will start with a simple table, see why it fails and then fix it using virtual scrolling and server-side data fetching.</p><p>Let&rsquo;s make this work in a real project.</p><h2 id="setting-up-the-project">Setting Up the Project</h2><p>First, create a new Angular application by running the command:</p><pre class=" language-bash"><code class="prism  language-bash">ng new superbowl-dashboard
</code></pre><p>Navigate to the project:</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">cd</span> superbowl-dashboard
</code></pre><p>Now install the Angular Grid. The <code>ng add</code> command handles dependencies and theme configuration for us:</p><pre class=" language-bash"><code class="prism  language-bash">ng add @progress/kendo-angular-grid --skip-confirmation
</code></pre><p>This installs the grid package and its peer dependencies and sets up the Kendo UI default theme.</p><p>Once the installation is done, we need to activate our Kendo UI license. This step removes the watermark and unlocks all the features.</p><blockquote><p>Don&rsquo;t have a license? Don&rsquo;t worry! You can get a <a target="_blank" href="https://www.telerik.com/try/kendo-ui">completely free trial</a> with <strong>no credit card required</strong>, so you can follow along and build the dashboard without worrying about the watermark.</p></blockquote><p>To do this, download the license key file from your Telerik account. Then, run this command inside your project folder:</p><pre class=" language-bash"><code class="prism  language-bash">npx kendo-ui-license activate
</code></pre><p>Because the Kendo UI Grid is so robust, it includes many features that can slightly increase the initial bundle size. We need to prevent Angular from throwing a &ldquo;bundle initial exceeded maximum budget&rdquo; error when we run or build an app. Open the <code>angular.json</code> file and increase the <code>budgets</code> config for the <code>initial</code> type to around <code>5MB</code> for warnings and <code>10MB</code> for errors.</p><p>Perfect! We have a fresh Angular project with Kendo UI Grid installed and styled. Now let&rsquo;s generate our Super Bowl viewers&rsquo; fake data.</p><h2 id="generating-one-million-viewers">Generating One Million Viewers</h2><p>Before we start with the grid, we need data. We&rsquo;ll create a single service that handles everything: generating fake viewer data for client-side demos and simulating a paginated server API for server-side scrolling.</p><p>To create the service, open the terminal and run the following Angular CLI command:</p><pre class=" language-bash"><code class="prism  language-bash">ng g s services/viewer
</code></pre><p>First, we will define a simple <code>Viewer</code> interface so our grid knows what fields to expect. Then, our service will include a <code>generateViewers</code> method to create mock data, and a <code>fetchPage</code> method that simulates a paginated server API. We won&rsquo;t use <code>fetchPage</code> right away, but it will be ready for when we implement server-side virtual scrolling later.</p><p>Don&rsquo;t worry too much about the exact implementation of the helper methods; the main idea here is not how to generate fake users, but how to create a grid capable of supporting massive amounts of data without breaking a sweat!</p><p>Open <code>src/app/services/viewer.ts</code> and add the following:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Injectable <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/core"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">Viewer</span> <span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
  username<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
  watchTimeMin<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
  isLive<span class="token punctuation">:</span> <span class="token keyword">boolean</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">PagedResult</span> <span class="token punctuation">{</span>
  data<span class="token punctuation">:</span> Viewer<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  total<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> ADJECTIVES <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token string">"Swift"</span><span class="token punctuation">,</span>
  <span class="token string">"Lucky"</span><span class="token punctuation">,</span>
  <span class="token string">"Bold"</span><span class="token punctuation">,</span>
  <span class="token string">"Chill"</span><span class="token punctuation">,</span>
  <span class="token string">"Epic"</span><span class="token punctuation">,</span>
  <span class="token string">"Happy"</span><span class="token punctuation">,</span>
  <span class="token string">"Lazy"</span><span class="token punctuation">,</span>
  <span class="token string">"Wild"</span><span class="token punctuation">,</span>
  <span class="token string">"Cool"</span><span class="token punctuation">,</span>
  <span class="token string">"Fast"</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> NOUNS <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token string">"Fan"</span><span class="token punctuation">,</span>
  <span class="token string">"Eagle"</span><span class="token punctuation">,</span>
  <span class="token string">"Tiger"</span><span class="token punctuation">,</span>
  <span class="token string">"Bear"</span><span class="token punctuation">,</span>
  <span class="token string">"Wolf"</span><span class="token punctuation">,</span>
  <span class="token string">"Hawk"</span><span class="token punctuation">,</span>
  <span class="token string">"Fox"</span><span class="token punctuation">,</span>
  <span class="token string">"Lion"</span><span class="token punctuation">,</span>
  <span class="token string">"Shark"</span><span class="token punctuation">,</span>
  <span class="token string">"Bull"</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>

@<span class="token function">Injectable</span><span class="token punctuation">(</span><span class="token punctuation">{</span> providedIn<span class="token punctuation">:</span> <span class="token string">"root"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">ViewerService</span> <span class="token punctuation">{</span>
  <span class="token keyword">private</span> readonly TOTAL_VIEWERS <span class="token operator">=</span> 1_000_000<span class="token punctuation">;</span>

  <span class="token function">generateViewers</span><span class="token punctuation">(</span>count<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">,</span> startId <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">:</span> Viewer<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> viewers<span class="token punctuation">:</span> Viewer<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> count<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      viewers<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        id<span class="token punctuation">:</span> startId <span class="token operator">+</span> i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span>
        username<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">randomFrom</span><span class="token punctuation">(</span>ADJECTIVES<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">randomFrom</span><span class="token punctuation">(</span>NOUNS<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">randomBetween</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">9999</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">,</span>
        watchTimeMin<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">randomBetween</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">240</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        isLive<span class="token punctuation">:</span> Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0.08</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">return</span> viewers<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">/**
   * Simulates a server API call with pagination.
   * Uses a small delay to mimic real network latency.
   */</span>
  <span class="token keyword">async</span> <span class="token function">fetchPage</span><span class="token punctuation">(</span>skip<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">,</span> take<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span><span class="token punctuation">:</span> Promise<span class="token operator">&lt;</span>PagedResult<span class="token operator">&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">await</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span>resolve<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> <span class="token number">80</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> <span class="token punctuation">{</span>
      data<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">generateViewers</span><span class="token punctuation">(</span>take<span class="token punctuation">,</span> skip<span class="token punctuation">)</span><span class="token punctuation">,</span>
      total<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>TOTAL_VIEWERS<span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">private</span> randomFrom<span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>arr<span class="token punctuation">:</span> T<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">:</span> T <span class="token punctuation">{</span>
    <span class="token keyword">return</span> arr<span class="token punctuation">[</span>Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> arr<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">private</span> <span class="token function">randomBetween</span><span class="token punctuation">(</span>min<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">,</span> max<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">number</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span>max <span class="token operator">-</span> min <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">+</span> min<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Each viewer has a fun auto-generated username (like <code>SwiftEagle4821</code>), their watch time and a live status. The <code>fetchPage</code> method is an <code>async</code> function that simulates a paginated API with a small delay to mimic network latency. We&rsquo;ll use <code>generateViewers</code> first and come back to <code>fetchPage</code> later.</p><p>With our service ready, let&rsquo;s see what happens when we try to render all these viewers at once.</p><h2 id="the-problem-rendering-all-rows-at-once">The Problem: Rendering All Rows at Once</h2><p>Let&rsquo;s try to do it and experience the problem firsthand. Open <code>src/app/app.ts</code> and replace its content:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component<span class="token punctuation">,</span> inject<span class="token punctuation">,</span> signal <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/core"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> CommonModule <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/common"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> ViewerService<span class="token punctuation">,</span> Viewer <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./services/viewer"</span><span class="token punctuation">;</span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">"app-root"</span><span class="token punctuation">,</span>
  standalone<span class="token punctuation">:</span> <span class="token keyword">true</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>CommonModule<span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl<span class="token punctuation">:</span> <span class="token string">"./app.html"</span><span class="token punctuation">,</span> 
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token punctuation">{</span>
  <span class="token keyword">private</span> viewerService <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>ViewerService<span class="token punctuation">)</span><span class="token punctuation">;</span>
  viewers <span class="token operator">=</span> signal<span class="token operator">&lt;</span>Viewer<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">loadViewers</span><span class="token punctuation">(</span>count<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>viewerService<span class="token punctuation">.</span><span class="token function">generateViewers</span><span class="token punctuation">(</span>count<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>viewers<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Now, let&rsquo;s open our template file, <code>src/app/app.html</code> and add a few buttons for 1K, 10K and 100K viewers. These buttons will call our <code>loadViewers()</code> method to quickly generate different amounts of fake data.</p><p>Finally, we&rsquo;ll use the <code>&lt;kendo-grid&gt;</code> component in our template. The key property to pay attention to is <code>[data]="viewers()"</code>, which tells Kendo UI to read from our reactive signal and constantly display the list of viewers.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">&gt;</span></span>Super Bowl Viewers Dashboard<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Connected viewers: {{ viewers().length.toLocaleString() }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>actions<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loadViewers(1_000)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>1K Viewers<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loadViewers(10_000)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>10K Viewers<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loadViewers(100_000)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>100K Viewers<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loadViewers(1_000_000)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>1M Viewers<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>grid-container<span class="token punctuation">"</span></span><span class="token style-attr language-css"><span class="token attr-name"> <span class="token attr-name">style</span></span><span class="token punctuation">="</span><span class="token attr-value"><span class="token property">height</span><span class="token punctuation">:</span> <span class="token number">600</span>px<span class="token punctuation">;</span> <span class="token property">overflow</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span></span><span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>table</span> <span class="token attr-name">border</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span><span class="token style-attr language-css"><span class="token attr-name"> <span class="token attr-name">style</span></span><span class="token punctuation">="</span><span class="token attr-value"><span class="token property">width</span><span class="token punctuation">:</span> <span class="token number">100%</span><span class="token punctuation">;</span> <span class="token property">border-collapse</span><span class="token punctuation">:</span> collapse<span class="token punctuation">;</span></span><span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>thead</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>#<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Username<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Watch (min)<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Live<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>thead</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tbody</span><span class="token punctuation">&gt;</span></span>
      @for (viewer of viewers(); track viewer.id) {
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{ viewer.id }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{ viewer.username }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{ viewer.watchTimeMin }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{ viewer.isLive ? 'Yes' : 'No' }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">&gt;</span></span>
      }
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tbody</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>table</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Now we can run our app. Go to the terminal and execute the following command:</p><pre class=" language-bash"><code class="prism  language-bash">ng serve
</code></pre><p>This will start the local development server. Once it finishes compiling, open your browser and navigate to <code>http://localhost:4200</code>.</p><p>Click <strong>&ldquo;1K Viewers&rdquo;</strong> and it feels smooth. Click <strong>&ldquo;10K Viewers&rdquo;</strong> and you will notice a significant lag.</p><p>Now click <strong>&ldquo;100K Viewers&rdquo;</strong> &hellip; and watch the browser scream for help. The page will freeze, the scroll will be jumpy and you might even get the &ldquo;Page Unresponsive&rdquo; dialog.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-04/page-unresponsive-dialog.png?sfvrsn=bb5cb2ab_2" alt="Page Unresponsive dialog" /></p><p>We have seen the problem: standard HTML tables and simple loops cannot handle huge datasets. When you click the 1M Viewers button, the browser stops working.</p><p>OK, but how can we fix this?</p><h2 id="the-solution-angular-grid-withvirtual-scrolling">The Solution: Angular Grid withVirtual Scrolling</h2><p>If you read about Kendo UI, you know the Kendo UI Grid, but before we to start to use it, I want to explain &ldquo;virtual scrolling.&rdquo; Think of virtual scrolling like a camera moving over a big stadium. You only see the seats in the camera frame, maybe 50 seats. The stadium has 1,000,000 seats, but the camera doesn&rsquo;t need to show all of them at once. It only shows what is visible.</p><p>Kendo UI Grid does exactly this with one property: <code>scrollable="virtual"</code>. Let&rsquo;s use it.</p><p>First, update your <code>app.ts</code>. We need to import <code>KENDO_GRID</code> and remove the <code>CommonModule</code> because the grid will handle everything now:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component<span class="token punctuation">,</span> inject<span class="token punctuation">,</span> signal <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/core"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> KENDO_GRID <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@progress/kendo-angular-grid"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> ViewerService<span class="token punctuation">,</span> Viewer <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./services/viewer"</span><span class="token punctuation">;</span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">"app-root"</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>KENDO_GRID<span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl<span class="token punctuation">:</span> <span class="token string">"./app.html"</span><span class="token punctuation">,</span> 
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token punctuation">{</span>
  <span class="token keyword">private</span> viewerService <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>ViewerService<span class="token punctuation">)</span><span class="token punctuation">;</span>
  viewers <span class="token operator">=</span> signal<span class="token operator">&lt;</span>Viewer<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">loadViewers</span><span class="token punctuation">(</span>count<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>viewerService<span class="token punctuation">.</span><span class="token function">generateViewers</span><span class="token punctuation">(</span>count<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>viewers<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Now, let&rsquo;s update <code>src/app/app.html</code>. We will replace the standard <code>&lt;table&gt;</code> with the <code>&lt;kendo-grid&gt;</code> component:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">&gt;</span></span>Super Bowl Viewers Dashboard<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Connected viewers: {{ viewers().length.toLocaleString() }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>actions<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loadViewers(10_000)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>10K<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loadViewers(100_000)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>100K<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loadViewers(1_000_000)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>1M<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>kendo-grid</span>
  <span class="token attr-name">[data]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>viewers()<span class="token punctuation">"</span></span>
  <span class="token attr-name">[height]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>600<span class="token punctuation">"</span></span>
  <span class="token attr-name">scrollable</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>virtual<span class="token punctuation">"</span></span>
  <span class="token attr-name">[rowHeight]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>36<span class="token punctuation">"</span></span>
  <span class="token attr-name">[pageSize]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>50<span class="token punctuation">"</span></span>
<span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>kendo-grid-column</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>id<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">[width]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>70<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>kendo-grid-column</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>kendo-grid-column</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>username<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Username<span class="token punctuation">"</span></span> <span class="token attr-name">[width]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>180<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>kendo-grid-column</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>kendo-grid-column</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>watchTimeMin<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Watch (min)<span class="token punctuation">"</span></span> <span class="token attr-name">[width]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>110<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>kendo-grid-column</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>kendo-grid-column</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>isLive<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Live<span class="token punctuation">"</span></span> <span class="token attr-name">[width]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>70<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>kendo-grid-column</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>kendo-grid</span><span class="token punctuation">&gt;</span></span>
</code></pre><h3 id="why-does-this-work">Why Does This Work?</h3><p>We added three important properties to the <code>&lt;kendo-grid&gt;</code> to make it fast:</p><ol><li><strong><code>scrollable="virtual"</code></strong>: This tells Kendo UI: &ldquo;Don&rsquo;t create all the rows at once. Only create the ones the user can see right now.&rdquo;</li><li><strong><code>[rowHeight]="36"</code></strong>: The grid needs to know exactly how tall each row is. This helps the grid calculate the scroll position correctly.</li><li><strong><code>[pageSize]="50"</code></strong>: This is how many rows Kendo UI keeps in the DOM. A good tip: set this to <strong>3 times</strong> the number of rows visible on your screen.</li></ol><p>Now, if you click the buttons, you will see that a page with 10,000, 100,000 or even <strong>one million viewers</strong> scrolls smoothly. The browser is fast because only ~50 rows are in the DOM at any time.</p><p>Kendo UI Grid does all the hard work for the rendering.</p><p>But there is one more problem. We fixed the <strong>rendering</strong>, but we are still loading one million records into the browser&rsquo;s memory. For a real app, loading 1,000,000 records at once is a bad idea. It uses too much RAM and it is slow to start.</p><p>What if we want to show one million users in real-time without using all the RAM? Let&rsquo;s use the final solution: <strong>Server-Side Data Fetching</strong>.</p><h2 id="server-side-data-fetching-with-endless-scrolling">Server-Side Data Fetching with Endless Scrolling</h2><p>Here&rsquo;s the reality: the Super Bowl has <strong>120 million viewers</strong>. We can&rsquo;t load all of them into the browser at once. Instead, the grid should fetch data page by page as the user scrolls , loading only what&rsquo;s needed, when it&rsquo;s needed.</p><p>Kendo UI Grid supports this out of the box with the <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/grid/api/gridcomponent#scrollbottom"><code>scrollBottom</code></a> event. When the user scrolls to the bottom of the current data, the grid fires this event, and we simply fetch the next page and append it. Let&rsquo;s build it!</p><p>Generate a new component by running the command in the terminal:</p><pre class=" language-bash"><code class="prism  language-bash">ng g c components/live-grid
</code></pre><p>Open <code>src/app/components/live-grid/live-grid.ts</code> and replace the content with:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component<span class="token punctuation">,</span> inject<span class="token punctuation">,</span> signal<span class="token punctuation">,</span> ChangeDetectionStrategy <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/core"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> KENDO_GRID <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@progress/kendo-angular-grid"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> ViewerService<span class="token punctuation">,</span> Viewer <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"../../services/viewer"</span><span class="token punctuation">;</span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">"app-live-grid"</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>KENDO_GRID<span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl<span class="token punctuation">:</span> <span class="token string">"./live-grid.html"</span><span class="token punctuation">,</span>
  changeDetection<span class="token punctuation">:</span> ChangeDetectionStrategy<span class="token punctuation">.</span>OnPush<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">LiveGrid</span> <span class="token punctuation">{</span>
  <span class="token keyword">private</span> viewerService <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>ViewerService<span class="token punctuation">)</span><span class="token punctuation">;</span>

  isConnected <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token keyword">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  loading <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token keyword">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  viewers <span class="token operator">=</span> signal<span class="token operator">&lt;</span>Viewer<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  pageSize <span class="token operator">=</span> 1_000<span class="token punctuation">;</span>

  <span class="token function">connect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>isConnected<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token keyword">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">loadMore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token function">onScrollBottom</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">loading</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">loadMore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">private</span> <span class="token function">loadMore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>loading<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token keyword">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    <span class="token keyword">this</span><span class="token punctuation">.</span>viewerService<span class="token punctuation">.</span><span class="token function">fetchPage</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">viewers</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>length<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>pageSize<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>viewers<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">(</span>current<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token operator">...</span>current<span class="token punctuation">,</span> <span class="token operator">...</span>result<span class="token punctuation">.</span>data<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>loading<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token keyword">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>The logic here is straightforward. First, <code>connect()</code> starts the process by fetching the initial data page using <code>loadMore()</code>. Then, whenever the user scrolls to the bottom of the grid, the <code>(scrollBottom)</code> event fires, triggering <code>onScrollBottom()</code> to fetch and append the next chunk of data to our <code>viewers</code> signal.</p><p>To make this work in the UI, we just need to set <code>scrollable="scrollable"</code> on our Kendo Grid to enable endless scrolling, and bind our <code>loading</code> signal to show a skeleton animation during the fetch.</p><p>Now let&rsquo;s build the template in <code>src/app/components/live-grid/live-grid.html</code> to tie all of this together:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">&gt;</span></span>Live Server Feed<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Viewers: {{ viewers().length }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>connect()<span class="token punctuation">"</span></span> <span class="token attr-name">[disabled]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>isConnected()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Connect to Live Feed<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>

@if (isConnected()) {
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>kendo-grid</span> 
    <span class="token attr-name">[data]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>viewers()<span class="token punctuation">"</span></span> 
    <span class="token attr-name">[height]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>600<span class="token punctuation">"</span></span> 
    <span class="token attr-name">scrollable</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>scrollable<span class="token punctuation">"</span></span>
    <span class="token attr-name">[loading]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loading()<span class="token punctuation">"</span></span>
    <span class="token attr-name">(scrollBottom)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>onScrollBottom()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>kendo-grid-column</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>id<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">[width]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>70<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>kendo-grid-column</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>kendo-grid-column</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>username<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Username<span class="token punctuation">"</span></span> <span class="token attr-name">[width]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>180<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>kendo-grid-column</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>kendo-grid-column</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>watchTimeMin<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Watch (min)<span class="token punctuation">"</span></span> <span class="token attr-name">[width]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>110<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>kendo-grid-column</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>kendo-grid-column</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>isLive<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Live<span class="token punctuation">"</span></span> <span class="token attr-name">[width]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>70<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>kendo-grid-column</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>kendo-grid</span><span class="token punctuation">&gt;</span></span>
}
</code></pre><p>Wire the component into the app. Update <code>app.ts</code>:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/core"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> LiveGrid <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./components/live-grid/live-grid"</span><span class="token punctuation">;</span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">"app-root"</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>LiveGrid<span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl<span class="token punctuation">:</span> <span class="token string">"./app.html"</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre><p>And <code>src/app/app.html</code>:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">&gt;</span></span>Super Bowl Viewers Dashboard<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>app-live-grid</span> <span class="token punctuation">/&gt;</span></span>
</code></pre><p>Run <code>ng serve</code>, open <code>http://localhost:4200</code> and click &ldquo;Connect to Live Feed.&rdquo;</p><p>You&rsquo;ll see the grid load the first 1,000 viewers. Now scroll down. When you reach the bottom, the grid fetches the next 1,000 viewers and appends them and the loading skeleton appears briefly while data is being fetched. Keep scrolling, and watch the viewers counter grow until it gets to 1,000,000. Yeah!!</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-04/grid-scroll.gif?sfvrsn=56a027cd_2" alt="Super Bowl viewers dashboard being scrolled and scrolled, very smoothly" /></p><h2 id="recap">Recap</h2><p>We saw the problem: rendering thousands of rows at once makes the browser freeze. Then we added Kendo UI <strong>virtual scrolling</strong> with <code>scrollable="virtual"</code>. This is the secret to showing large datasets without crashing.</p><p>Finally, we used <strong>server-side data fetching</strong> with the <code>(scrollBottom)</code> event. The grid loads data page by page. This keeps the memory usage low and the experience smooth.</p><p>In your next challenge don&rsquo;t worry about the data, Kendo UI Grid makes it easy. With a few properties, your dashboard can handle millions of rows. ✌</p><p>Give it a try for free!</p><p><a href="https://www.telerik.com/try/kendo-angular-ui" target="_blank" class="Btn">Try Kendo UI for Angular</a></p><p>Happy coding!</p><p>Source Code: <a target="_blank" href="https://github.com/danywalls/kendo-grid-large-app">https://github.com/danywalls/kendo-grid-large-app</a></p><img src="https://feeds.telerik.com/link/23055/17323038.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:f462deac-a01d-48d3-9fca-87eea0bb03f4</id>
    <title type="text">The 10 Best Angular UI Libraries</title>
    <summary type="text">TL;DR What’s the best Angular UI library? If you’re looking for build speed thanks to robust components, AI capabilities, built-in design options and a ready support community, the Progress Kendo UI for Angular library is hard to beat.</summary>
    <published>2026-04-16T14:51:07Z</published>
    <updated>2026-09-02T08:08:54Z</updated>
    <author>
      <name>Dany Paredes </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17320236/10-best-angular-ui-libraries"/>
    <content type="text"><![CDATA[<p><span class="featured"><strong>TL;DR What&rsquo;s the best Angular UI library?</strong> If you&rsquo;re looking for build speed thanks to robust components, AI capabilities, built-in design options and a ready support community, the Progress Kendo UI for Angular library is hard to beat.</span></p><p>I&rsquo;ve been developing software for more than 15 years, and the industry never stops changing. Choosing a framework is a strategic decision that must fit the time we are building in.</p><p>Building apps in 2026 is very different from 2015, 2020 or even 2025. Today, picking a UI library is more complex than before. We are no longer just building simple &ldquo;forms and tables&rdquo;; we are building AI-powered experiences. As developers, we now work with AI agents like Cursor and Copilot, and our UI library must be ready for AI from day one.</p><p>The best Angular library does not just save time with CSS or provide basic typical components; it must provide components and tools to help AI and agents understand our code better, saving tokens, time and money for your company, and also help the entire team to work better.</p><p>But as always, the best way to explain the importance of this choice is to look at a real-world situation.</p><h2 id="the-scenario">The Scenario</h2><p>Imagine you were just hired by a startup. You must deliver a complex platform quickly to compete in the market, but your app is modern in the AI era, so it needs more than basic grids and buttons. It will also have complex calendars, real-time charts, chat interfaces and anything needed to perform in accordance with modern user expectations &hellip; and it needs to help our new teammates (AI coding agents) work better and faster.</p><p>In this situation, your UI library is not just about delivering on time. It is about providing a tool that can help you ship your project, support your team with very stable code and provide complex features so you don&rsquo;t have to build everything from zero. You need a library that is already &ldquo;AI-ready,&rdquo; with components made for AI agents and chat interfaces.</p><blockquote><p>I can tell you, from experience, picking the wrong library can mean months of extra work and watching your competitors launch while you are still fixing basic things.</p></blockquote><p>Today, we are going to dive into each framework, showing its strengths and weaknesses, and finally my recommendation for each scenario.</p><h2 id="kendo-ui-for-angular">1. Kendo UI for Angular</h2><p>In the scenario we described, the Progress <a target="_blank" href="https://www.telerik.com/kendo-angular-ui">Kendo UI for Angular</a> component library is your best all-in-one framework. When the deadline is close and the project is high-priority, you do not have time to build everything from scratch.</p><h3 id="why-kendo-ui-is-the-best-tool-for-projects">Why Kendo UI Is the Best Tool for Projects</h3><ul><li><p><strong>Built for speed:</strong> With <strong><a target="_blank" href="https://www.telerik.com/kendo-angular-ui#components">120+ components</a></strong> (Grid, Excel, Charts, Scheduler, etc.) and ready-to-use <a target="_blank" href="https://www.telerik.com/page-templates-and-ui-blocks"><strong>Page Templates</strong></a>, you will be assembling your app quickly. You can save <em>weeks</em> of work and focus on the important parts of your code while an entire team at Progress manages the upkeep of your component library.</p></li><li><p><strong><a target="_blank" href="https://www.telerik.com/mcp-servers">MCP Server</a>:</strong> Kendo UI is an AI-ready framework for developers and agents to increase productivity. Today, every hour (and token) is valuable. The Kendo UI MCP Server helps your AI agents (like VS Code or Cursor) write better code by following Kendo UI best practices that come directly from the team that built the software, reducing hallucinations and allowing your developers and agents ship code fast yet with the highest quality.</p></li><li><p><strong><a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-components">AI-ready Angular components</a>:</strong> Add intelligent features quickly with components like AIPrompt, SmartPaste or AI features in the Grid. This makes your app look modern with very little effort.</p></li><li><p><strong><a target="_blank" href="https://themebuilder.telerik.com/">ThemeBuilder</a>:</strong> Avoid wasting time on CSS. You can import design tokens from Figma and get your style right the first time without writing thousands of lines of code.</p></li><li><p><strong><a target="_blank" href="https://www.telerik.com/purchase/support-plans">Expert help:</a></strong> The tier-based support plans give you peace of mind. If you have a problem at a critical moment, you have a team of professional engineers to help you, not just a public forum (but the community support is also robust!).</p></li></ul><p><strong>Pro tip:</strong> You can <a target="_blank" href="https://www.telerik.com/try/kendo-angular-ui">try Kendo UI for Angular completely free</a> for 30 days, <strong>no credit card required</strong>. It&rsquo;s the fastest way to prove to your team that you can meet that &ldquo;impossible&rdquo; deadline.</p><p>But what if you are looking for Google&rsquo;s official baseline? That brings us to our next pick.</p><h2 id="angular-material">2. Angular Material</h2><p><a target="_blank" href="https://material.angular.io/">Angular Material</a> is the official UI suite maintained by the Angular team. It implements Google&rsquo;s Material Design and is often the first choice for developers looking for a standard, predictable foundation. While it&rsquo;s the community baseline, in 2026, many projects find its rigid structure a limiting factor.</p><p>If you&rsquo;ve ever worked in an Angular project, you&rsquo;ve probably used it. It&rsquo;s the industry standard for a reason, but standards aren&rsquo;t always enough for every project.</p><ul><li><p><strong>The Good:</strong> It is very stable. Because it is built by the same team that makes Angular, it always works with the latest versions. It follows Google&rsquo;s Material Design and looks clean and professional.</p></li><li><p><strong>The Cons:</strong> The customization is difficult. If you need a unique look for your brand, you will spend a lot of time fighting with CSS. It also lacks advanced components for big data, like high-performance Grids or Calendars.</p></li><li><p><strong>My Feedback:</strong> I have seen many teams spend weeks trying to make Material look different. Also, Material lacks complex tools like a <strong>Scheduler</strong> or a <strong>Gantt Chart</strong>. If your project needs more than just basic forms, I recommend <strong>Kendo UI</strong>. It gives you 120+ advanced parts that are ready for big business needs, saving you the work of building them yourself.</p></li></ul><p>If Material feels too rigid and you need a massive variety of &ldquo;out-of-the-box&rdquo; gadgets, you might want to consider our next option.</p><h2 id="primeng">3. PrimeNG</h2><p><a target="_blank" href="https://primeng.org/">PrimeNG</a> is one of the well-known libraries in the ecosystem with a collection of components. While its catalog is extensive, navigating its many options can require a significant investment in terms of styling and consistency in larger apps.</p><ul><li><p><strong>The Good:</strong> Their variety is unmatched. PrimeNG has many components from simple buttons to complex organization charts.</p></li><li><p><strong>The Cons:</strong> Maintaining a perfectly consistent visual style across many complex components can become tricky in large-scale projects. The styling system can sometimes feel overwhelming when you need deep, unified brand customization.</p></li><li><p><strong>My Feedback:</strong> Kendo UI provides more than just a framework. It offers tools like ThemeBuilder, Figma kits, MCP tools and AI-ready components to provide a smooth developer experience.</p></li></ul><p>Now, if your project is heavily focused on data and complex dashboards, check out the next player in the game.</p><h2 id="syncfusion-angular">4. Syncfusion Angular</h2><p><a target="_blank" href="https://www.syncfusion.com/angular-ui-components">Syncfusion</a> is an enterprise-focused suite that offers a wide range of specialized components.</p><ul><li><p><strong>The Good:</strong> Their charts and grids are powerful. They are a good choice for data-heavy applications and dashboards.</p></li><li><p><strong>The Cons:</strong> The API does not always feel like standard Angular, which makes it harder to learn. It is also difficult to customize the components to match a Figma design. This is a framework built for developers, but real-world projects need to include the whole team.</p></li><li><p><strong>My Feedback:</strong> We should not waste time manually syncing Figma styles with components. I prefer Kendo UI because it is designed for developers, designers and AI agents. This provides a smooth experience for everyone on the team.</p></li></ul><p>Speaking of data apps, sometimes you don&rsquo;t need a full suite. If your app is 90% tables, then you should take a look at the next one.</p><h2 id="ag-grid">5. AG Grid</h2><p><a target="_blank" href="https://www.ag-grid.com/angular-data-grid/">AG Grid</a> is a specialized library almost entirely focused on data grids. It&rsquo;s a common choice for applications where tabular data is the main focus, though it requires pairing with other libraries for common UI elements like buttons and modals.</p><ul><li><p><strong>The Good:</strong> If your application is 90% tables, this is a great choice. Its performance with very large datasets is good.</p></li><li><p><strong>The Cons:</strong> The real world is not only a grid. You will still need to find and style other libraries to solve other scenarios in your app, often resulting in a UI with inconsistent styles that is hard to maintain.</p></li><li><p><strong>My Feedback:</strong> AG Grid is powerful, but it is only one part of what you&rsquo;ll need. Kendo UI gives you that same grid power in a <strong>unified system</strong>. This means your Grid, Buttons and Charts all share the same style and logic. Plus, Kendo UI has built-in <strong>PDF and Excel exporting</strong> that works perfectly without extra work.</p></li></ul><p>But what if you need that speed in more than just tables? Let&rsquo;s see the next option.</p><h2 id="ignite-ui-for-angular">6. Ignite UI for Angular</h2><p><a target="_blank" href="https://www.infragistics.com/products/ignite-ui-angular">Ignite UI for Angular</a> is focused on data visualization and performance. It&rsquo;s often used in scenarios where real-time charts are a priority, though its ecosystem is smaller than other major players.</p><ul><li><p><strong>The Good:</strong> Great charts and a very fast rendering engine, especially for real-time data.</p></li><li><p><strong>The Cons:</strong> The ecosystem and community are smaller than the large libraries on this list. This can make it harder to find help for specific problems. Also, similar to AG Grid, in the real world our apps are more than a dashboard. They work with a combination of features that take time to build by yourself.</p></li><li><p><strong>My Feedback:</strong> Unlike Ignite UI, Kendo UI has Building Blocks that can solve common scenarios like login, register, forgot password, etc. Kendo UI has a very large community and <strong>professional support</strong>. This means you can always get help when you are stuck, making it a safer choice for important projects.</p></li></ul><p>If you&rsquo;re already familiar with the DevExpress environment from other platforms, then you&rsquo;ll feel right at home with our next pick.</p><h2 id="devextreme-angular">7. DevExtreme Angular</h2><p><a target="_blank" href="https://js.devexpress.com/Angular/">DevExtreme Angular</a> by DevExpress has its roots in traditional software development, carrying over patterns from WinForms and ASP.NET. This makes it a familiar choice for teams coming from a more classical enterprise background, though its developer experience can feel a bit dated for modern web standards.</p><ul><li><p><strong>The Good:</strong> Perfect for developers who already use DevExpress and need complex reporting tools and traditional business components.</p></li><li><p><strong>The Cons:</strong> It can feel a bit &ldquo;old&rdquo; in terms of how you write code. Changing the CSS to meet modern web standards is often a difficult and long task.</p></li><li><p><strong>My Feedback:</strong> To avoid the old code patterns of DevExtreme, Kendo UI offers a clean, <strong>modern architecture</strong>. It helps you build fast without creating messy code that is hard to fix later.</p></li></ul><p>For those who prefer a clean, minimal design system like Ant Design, there&rsquo;s a popular community implementation you should know about.</p><h2 id="ng-zorro">8. NG-ZORRO</h2><p><a target="_blank" href="https://ng.ant.design/">NG-ZORRO</a> is a community-driven implementation of the Ant Design system for Angular. It&rsquo;s aimed at developers who want a ready-made aesthetic for dashboards. However, its community-based nature means it lacks the dedicated professional support found in commercial suites.</p><ul><li><p><strong>The Good:</strong> It creates beautiful and professional-looking interfaces immediately. Excellent for internal tools where speed is important.</p></li><li><p><strong>The Cons:</strong> It is very strict about its design. If you need to change the style or keep the same look across React or Vue teams, you will find it limited.</p></li><li><p><strong>My Feedback:</strong> Community libraries like NG-ZORRO are good until you find a difficult bug. In a startup, time is money. Kendo UI enterprise support gets you help from the engineers who actually built the tools. This <strong>professional protection</strong> is why big companies prefer Kendo UI.</p></li></ul><p>If your focus is less on &ldquo;fancy&rdquo; and more on extreme accessibility and enterprise clean-room aesthetics, then check this out.</p><h2 id="clarity-design-system">9. Clarity Design System</h2><p><a target="_blank" href="https://clarity.design/">Clarity</a> is a design system developed by VMware. It was built for their own internal products and emphasizes a specific enterprise-style UX. While it&rsquo;s highly focused on its specific patterns, customizing it to fit a broader range of brand identities can be a challenge.</p><ul><li><p><strong>The Good:</strong> Strong focus on user experience and accessibility. It is built by VMware, so it is proven to work well for complex business tasks.</p></li><li><p><strong>The Cons:</strong> The look is very specific to VMware. It is difficult to change the style for a brand that wants to look unique.</p></li><li><p><strong>My Feedback:</strong> Clarity is very accessible, but it is hard to change. If your designers use Figma, Kendo UI is a much better choice. Progress Kendo UI provides <strong>Figma UI Kits</strong> that match the components exactly. This means your developers can build exactly what the designers created without mistakes.</p></li></ul><p>Finally, if you are the type of developer who loves full modularity and building your own patterns like LEGO, you&rsquo;ll love our final pick.</p><h2 id="taiga-ui">10. Taiga UI</h2><p><a target="_blank" href="https://taiga-ui.dev/">Taiga UI</a> is a library that focuses on modularity and a TypeScript-first approach. It&rsquo;s designed for developers who enjoy building their UI piece by piece, though this modularity often means a slower development cycle compared to more pre-integrated solutions.</p><ul><li><p><strong>The Good:</strong> It uses modular principles, making it perfect for developers who want to build their own patterns from zero.</p></li><li><p><strong>The Cons:</strong> Building a complex business dashboard this way is a slow process. In a startup, you don&rsquo;t have months to build every part; you have weeks to launch.</p></li><li><p><strong>My Feedback:</strong> Taiga UI is fun for small experiments, but for real business, you need speed. Kendo UI gives you the same modular power but with <strong>120+ ready-to-use components</strong>. You don&rsquo;t have to build the &ldquo;LEGO blocks&rdquo; yourself. Kendo UI gives you the whole castle ready to use.</p></li></ul><h2 id="recap">Recap</h2><p>Today, building software is a team effort. It is for designers, developers and AI agents. Choosing a framework that thinks about all these factors is the key to a successful product.</p><p>In 2026, picking a framework is a strategic decision that defines the success of your project. Choosing <strong>Kendo UI for Angular</strong> means giving your team the best tools for modern development. With features like the <a target="_blank" href="https://www.telerik.com/mcp-servers"><strong>MCP Server</strong></a>, <a target="_blank" href="https://themebuilder.telerik.com/"><strong>ThemeBuilder</strong></a> and <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-components"><strong>AI-ready components</strong></a>, Kendo UI for Angular helps you build applications faster and handle future challenges.</p><p><strong>Do you want to try it?</strong> </p><p><a target="_blank" href="https://www.telerik.com/try/kendo-angular-ui" class="Btn">Download Free Trial</a></p><img src="https://feeds.telerik.com/link/23055/17320236.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:9bf61f7e-e7a4-44d4-aba4-e8c1fc74615b</id>
    <title type="text">Progress Telerik Agentic UI Generator vs. Syncfusion Agentic UI Builder</title>
    <summary type="text">See how the AI-based UI creation tools from devtools powerhouses Progress and Syncfusion stack up when they go head to head.</summary>
    <published>2026-04-08T16:38:33Z</published>
    <updated>2026-09-02T08:08:54Z</updated>
    <author>
      <name>Hassan Djirdeh </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17315935/progress-telerik-agentic-ui-generator-vs-syncfusion-agentic-ui-builder"/>
    <content type="text"><![CDATA[<p><span class="featured">See how the AI-based UI creation tools from devtools powerhouses Progress and Syncfusion stack up when they go head to head. </span></p><p>AI-powered code generation has become a significant part of how developers build user interfaces. The <a target="_blank" href="https://survey.stackoverflow.co/2025/ai/#1-ai-tools-in-the-development-process">2025 Stack Overflow Developer Survey</a> found that 84% of developers are now using or planning to use AI tools in their development process.</p><p>Original AI adoption has been through tools like code autocompletion and chat-based assistants, but agentic UI tools take things further. Rather than suggesting the next line of code, they can take a natural language prompt and produce working, styled UI code in seconds.</p><p>However, not all AI generation tools are created equal. The quality of the output, how reliably it builds on the first attempt, how fast it runs and how well it handles things like accessibility and theming can vary quite a bit between tools. These differences matter because a tool that requires a large number of follow-up prompts to correct errors or produce code that doesn&rsquo;t match the original requirements isn&rsquo;t truly saving us time.</p><p>In this article, we&rsquo;ll look at a head-to-head comparison between two agentic UI generation tools: the <strong>Progress Telerik Agentic UI Generator</strong> which includes the <a target="_blank" href="https://www.telerik.com/blazor-ui/documentation/ai/agentic-ui-generator/getting-started">Blazor Agentic UI Generator for .NET/Blazor</a> and the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-tools/agentic-ui-generator/getting-started">Kendo UI Generator for Angular and React</a>, and the <a target="_blank" href="https://www.syncfusion.com/explore/agentic-ui-builder/"><strong>Syncfusion Agentic UI Builder</strong></a>. We&rsquo;ll walk through the results of extensive testing across multiple frameworks, covering output quality, performance, stability, accessibility, theming and more.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-04/progress-vs-syncfusion.jpg?sfvrsn=d281e72b_2" alt="Progress Telerik vs. Syncfusion" /></p><h2 id="how-the-comparison-was-conducted">How the Comparison Was Conducted</h2><p>To make this comparison as fair and thorough as possible, both tools were tested across multiple frameworks using two evaluation approaches.</p><h3 id="blazor.net">Blazor/.NET</h3><p>On the Blazor/.NET side, 23 prompts were run through the Telerik Agentic UI Generator and the Syncfusion Agentic UI Builder. These prompts ranged from simple single-component requests to complex multi-section layouts like e-commerce catalog pages and CMS admin dashboards. Each prompt&rsquo;s output was rated on a 0 to 7 scale:</p><ul><li><strong>0-1</strong>: Doesn&rsquo;t build or crashes with no UI</li><li><strong>2-3</strong>: Partially renders, major sections broken</li><li><strong>4</strong>: Renders but requires multiple prompts to clear build or runtime errors</li><li><strong>5</strong>: Renders but doesn&rsquo;t match prompt requirements in several areas</li><li><strong>6</strong>: Mostly complete, minor issues</li><li><strong>7</strong>: Fully matches requirements</li></ul><p>The evaluation also tracked how many prompts were needed before the output could successfully build and render, as well as the time (in seconds) from initial prompt submission to output generation.</p><h3 id="angular-and-react">Angular and React</h3><p>For Angular and React, a dedicated evaluation was conducted comparing the Kendo Agentic UI Generator against the Syncfusion Agentic UI Builder. Rather than scoring individual prompts, this evaluation focused on a technical comparison of the tools themselves. By running many prompts and examining the context returned by each tool, the analysis compared how each MCP server helps the AI agent arrive at its output across categories like layout, styling, accessibility, documentation and component handling.</p><h2 id="output-quality-and-reliability">Output Quality and Reliability</h2><p>This is the category where the gap between the two tools becomes immediately clear.</p><p>Across the 23 Blazor prompts, the Telerik Agentic UI Generator consistently produced complete, requirement-matching output on the first attempt. The Syncfusion Agentic UI Builder told a different story. It experienced <strong>five failures</strong> where no usable UI was generated at all, and several other prompts that required follow-up prompts to fix errors before the output could even build. Let&rsquo;s look at a couple of examples.</p><h3 id="failures">Failures</h3><p>The very first prompt asked both tools to build a login screen with email/password validation and an admin dashboard with a sidebar menu, key metrics and recent activity.</p><p><strong>Prompt</strong>: <em>&ldquo;I have created an empty application that now needs a login screen and an admin dashboard. Add a login form with email/password fields and validation. After a successful login, redirect to an admin dashboard page featuring a sidebar menu and a main content area displaying key metrics and recent activity.&rdquo;</em></p><p>The Telerik Generator produced a fully working output on the first attempt.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-04/blazor-agentic-ui-prompt-1.png?sfvrsn=ead93eba_1" alt="Telerik UI Generator produced dashboard" /></p><p>The Syncfusion Builder returned an error along the lines of: <code>Error. This response is truncated because it is too long. Try rephrasing your question.</code> No UI was generated at all.</p><p>The second prompt told both tools to create a monitoring dashboard with system health KPIs, a log stream panel, charts for API response times and requests per service.</p><p><strong>Prompt</strong>: <em>&ldquo;Create a new page using the existing top navigation and footer. In the middle, add 3 rows with 3 responsive columns each. The top row shows system health KPIs for CPU, memory and error counts. The middle rows include a Log Stream panel, a line Chart of API response times and a bar chart of requests per service. The bottom row contains a Deployment History table, an Alerts panel and a list of open tickets.&rdquo;</em></p><p>The Telerik Generator again produced a fully working output on the first pass.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-04/blazor-agentic-ui-prompt-2.png?sfvrsn=150ecc0b_1" alt="Telerik Generator produced dashboard with graphs" /></p><p>The Syncfusion Builder hit the same truncation error.</p><p>These are the kinds of prompts that represent real-world use cases. A login screen with a dashboard and a monitoring page with multiple data panels aren&rsquo;t unusual requests.</p><h3 id="errors-requiring-follow-ups">Errors Requiring Follow-ups</h3><p>Not every issue is an error during the generation process. Some prompts produced output that needed additional work to get running.</p><p>We fired a prompt to ask for a product catalog page with a responsive layout, product cards, a filtering toolbar and expandable detail views. The Telerik Generator handled it cleanly on the first attempt. The Syncfusion Builder hit an error about a missing component parameter and needed a second follow-up prompt to fix it.</p><p><strong>Prompt</strong>: <em>&ldquo;Create a product catalog page with a responsive CSS layout. The layout should display product cards. Add a toolbar with filtering options, and expandable detail view for each product that work seamlessly on mobile, tablet, and desktop.&rdquo;</em></p><p>The first output by the Telerik Blazor generator:</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-04/blazor-agentic-ui-prompt-4.png?sfvrsn=5b3d958b_1" alt="Telerik Blazor AI UI Generator produced product catalog" /></p><p>The final output from Syncfusion, after the necessary follow-up prompt:</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-04/syncfusion-agentic-ui-prompt-4.png?sfvrsn=a91f64f0_1" alt="Syncfusion product catalog" /></p><p>The Syncfusion Builder&rsquo;s errors in these cases often involved referencing component parameters that don&rsquo;t exist, which may suggest the tool&rsquo;s AI agent is working with less reliable component information during generation.</p><h3 id="partial-results">Partial Results</h3><p>Not all issues showed up as crashes or errors needing follow-ups. Let&rsquo;s look at an example of a prompt that was made which involved a theming request.</p><p><strong>Prompt</strong>: <em>&ldquo;Generate a custom theme for a corporate blue and green color scheme with high contrast accessibility requirements.&rdquo;</em></p><p>The Telerik Agentic UI Generator created the output matching the requirements.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-04/blazor-agentic-ui-prompt-13.png?sfvrsn=ed53d11a_1" alt="Telerik Agentic UI generator blue n=and green" /></p><p>The Syncfusion Builder did create a custom theme, but the expected theme wasn&rsquo;t applied to the output.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-04/syncfusion-agentic-ui-prompt-13.png?sfvrsn=eaac1328_1" alt="Syncfusion green and blue missing" /></p><h3 id="the-bigger-picture">The Bigger Picture</h3><p>Even when we set aside the failures and only look at prompts where the Syncfusion Builder produced something usable, the outputs still frequently fell short of the original requirements.</p><p>On the Angular and React side, the findings were consistent. While the final rendered UI sometimes appeared similar at a glance, the most significant differences were in how each tool&rsquo;s MCP server helped the agent arrive at that output. The Kendo Generator&rsquo;s tools consistently delivered more relevant, targeted context to the AI agent, filtering results to what was actually needed for the prompt. The Syncfusion Builder&rsquo;s tools returned broader, less filtered responses, often including full component prop lists and governance rules regardless of what was asked.</p><h2 id="performance">Performance</h2><p>Speed matters when we&rsquo;re iterating on UI designs with AI. Waiting several minutes for a complex layout to generate can significantly slow down the development flow.</p><p>Across the Blazor evaluation, the Telerik Generator was consistently faster. The speed advantage was most noticeable on complex layout prompts. For example, on a complex e-commerce catalog page with filtering, sorting, responsive breakpoints and pagination, the Telerik Generator completed in about 799 seconds while the Syncfusion Builder took 908 seconds.</p><p>There was one outlier where Syncfusion was notably faster (a simpler single-component case), but across the full set of 23 prompts, the speed advantage consistently favored Telerik.</p><h2 id="accessibility">Accessibility</h2><p>Accessibility is often treated as an afterthought, but for enterprise applications, it&rsquo;s a requirement, not a nice-to-have!</p><p>The Kendo Generator includes a dedicated accessibility tool (<a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-tools/agentic-ui-generator/prompt-library#accessibility-assistant">#kendo_accessibility_assistant</a>) that retrieves WCAG 2.2 Level AA guidelines as a mandatory step in the generation process. It also fetches component-specific accessibility requirements for each component used in the output. This leads to every piece of generated UI having accessibility considerations baked in from the start.</p><p>From what we can gather, and at the time of writing, the Syncfusion Builder doesn&rsquo;t have a strong accessibility tool like the <code>#kendo_accessibility_assistant</code>.</p><h2 id="theming-layout-and-documentation">Theming, Layout and Documentation</h2><p>Beyond output quality and speed, the Angular and React evaluation revealed some important architectural differences in how each tool handles theming, layout and documentation.</p><h3 id="theming">Theming</h3><p><strong>Theming</strong> is more than color selection. The Kendo UI Generator produces a complete design system from a single prompt, including colors, typography, spacing scales, border radius, elevation and shadows. The Syncfusion Builder&rsquo;s style tool is limited to component state colors and semantic colors. Typography, spacing and elevation aren&rsquo;t reachable through it, so the generated output may look right in terms of color but lack the design coherence that holds a full application together.</p><h3 id="layout">Layout</h3><p><strong>Layout</strong> is also where a notable dependency difference comes in. The Kendo UI Generator uses a self-contained layout system built on its own CSS utilities, introducing no external dependencies. The Syncfusion Builder relies on <a target="_blank" href="https://tailwindcss.com/">Tailwind CSS</a>, injected into every project, and works from a catalog of 265+ prebuilt blocks. When the desired layout doesn&rsquo;t match a catalog entry, the result approximates what was asked for.</p><p>For teams already using Tailwind, this might feel natural but for projects on a different CSS framework (<a target="_blank" href="https://material.angular.dev/">Angular Material</a>, for example), adding Tailwind on top can introduce style conflicts. This can also be a potential blocker for organizations that restrict third-party dependencies.</p><p>Responsiveness follows a similar split: the Kendo UI Generator has a dedicated phase with explicit breakpoint reasoning, while the Syncfusion Builder inherits responsive behavior from Tailwind&rsquo;s defaults without any first-class responsive logic of its own.</p><h3 id="documentation">Documentation</h3><p><strong>Documentation</strong> plays a bigger role in output quality than it might seem, since it directly shapes how well the AI agent understands the components it&rsquo;s generating. The Kendo UI Generator injects relevant documentation chunks directly into every component tool call, including API references with full type signatures. The Syncfusion Builder treats documentation as a separate tool, triggered only by specific keywords. At the time of the evaluation, results from this tool were inconsistent and the service had been unavailable for over 24 hours for both Angular and React.</p><p>One other important observation from the Angular and React evaluation: the Kendo UI Generator customizes its workflow per prompt using confidence scores, including only the tools and instructions relevant to each request. The Syncfusion Builder runs the same fixed sequence for most prompts regardless of complexity, and its component tools return the full prop list and approximately 250 lines of governance rules on every call. The result is that <strong>the Kendo UI agent operates on targeted, preprocessed context while the Syncfusion agent carries a heavier payload for every request</strong>.</p><h2 id="wrap-up">Wrap-up</h2><p>The comparison across Blazor, Angular and React tells a consistent story with these agentic UI generators. The Progress Telerik Agentic UI Generator outperforms the Syncfusion Agentic UI Builder across output quality, reliability, performance, accessibility, theming, layout and documentation.</p><p>On the Blazor side, the Telerik Generator had zero full failures across 23 prompts while Syncfusion had five, along with a consistent speed advantage on complex prompts and more reliable first-pass output. On the Angular and React side, the advantages show up in the underlying architecture, where the Kendo Generator&rsquo;s tools consistently deliver cleaner, more relevant context to the AI agent.</p><hr /><blockquote><p>Get started with AI-empowered development. The <a target="_blank" href="https://www.telerik.com/mcp-servers">Kendo UI and Telerik AI tools</a> are ready. And they come as part of the free trial of the component libraries.</p><br /><p><a href="https://www.telerik.com/mcp-servers#how-to-try" class="Btn" target="_blank">Try Now</a></p></blockquote><hr /><p>For more information on the Progress Telerik Agentic UI Generator, check out the following resources:</p><ul><li><a target="_blank" href="https://www.telerik.com/blazor-ui/documentation/ai/agentic-ui-generator/getting-started">Telerik Agentic UI Generator for Blazor</a></li><li><a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/agentic-ui-generator/getting-started">Kendo UI Generator for Angular</a></li><li><a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-tools/agentic-ui-generator/getting-started">Kendo UI Generator for React</a></li></ul><p>The full comparison data referenced in this article is available for download:</p><ul><li><a target="_blank" href="https://www.telerik.com/docs/default-source/blogs-docs//syncfusion-builder-vs-telerik-generator-comparison.xlsx">Telerik UI for Blazor Agentic UI Generator vs Syncfusion Agentic UI Builder Comparative Evaluation (XLSX)</a></li><li><a target="_blank" href="https://www.telerik.com/docs/default-source/blogs-docs//syncfusion-ui-builder-vs-kendo-ui-generator.xlsx">Kendo Agentic UI Generator vs Syncfusion Agentic UI Builder (XLSX)</a></li></ul><hr /><h2 id="summary-faqs">Summary FAQs</h2><h3 id="what-do-these-tools-do">What Do These Tools Do?</h3><h4 id="what-telerik-agentic-ui-generator-is">What Telerik Agentic UI Generator Is</h4><p>According to the <a href="https://www.telerik.com/mcp-servers" target="_blank">Progress Telerik website</a>, the Telerik Agentic UI Generator for Telerik and Kendo UI libraries is an intelligent development tool delivered through the Model Context Protocol (MCP) Server that enables UI generation from natural language prompts. Once configured and authenticated, you can use the Agentic UI Generator tool (#telerik_ui_generator) together with the available specialized MCP assistants.</p><h4 id="what-syncfusion-agentic-ui-builder-is">What Syncfusion Agentic UI Builder Is</h4><p>According to the <a target="_blank" href="https://www.syncfusion.com/explore/agentic-ui-builder/">Syncfusion site</a>, Syncfusion&rsquo;s Agentic UI Builder is designed to work inside an IDE to generate UIs, dashboards or pages with Syncfusion components with natural language commands. Syncfusion uses MCP integration to access component APIs, prebuilt UI blocks, styling configurations, icon libraries and code generation.</p><h3 id="why-does-mcp-matter-in-both-products">Why Does MCP Matter in Both Products?</h3><p>Both brands&rsquo; tools use Model Context Protocol (MCP) servers to connect AI applications directly to the software specs for the individual library. This means that the AI is informed on component documentation, best practices, workflows and tooling provided by the UI library, so the AI can create a user interface more in line with how the library was designed to work. It should result in better outputs than if an AI were cobbling together an interface without guidance.</p><p>Learn more about the individual MCP servers:</p><ul><li><a href="https://www.telerik.com/blazor-mcp-servers" target="_blank">Telerik UI for Blazor MCP Servers</a></li><li><a href="https://www.telerik.com/angular-mcp-servers" target="_blank">Kendo UI for Angular MCP Servers</a></li><li><a href="https://www.telerik.com/react-mcp-servers" target="_blank">KendoReact MCP Servers</a></li><li><a target="_blank" href="https://ej2.syncfusion.com/react/documentation/mcp-server/overview">Syncfusion EJ2 React MCP Server</a></li><li><a target="_blank" href="https://ej2.syncfusion.com/angular/documentation/mcp-server/overview">Syncfusion EJ2 Angular MCP Server</a></li><li><a target="_blank" href="https://blazor.syncfusion.com/documentation/mcp-server/overview">Syncfusion Blazor MCP Server</a></li></ul><h3 id="are-prompt-libraries-included">Are Prompt Libraries Included?</h3><h4 id="telerik-and-kendo-ui-generator-prompt-libraries">Telerik and Kendo UI Generator Prompt Libraries</h4><p>Yes! Prompt libraries are included for the Kendo UI and Telerik AI UI Generator tools:</p><ul><li>Blazor: <a target="_blank" href="https://www.telerik.com/blazor-ui/documentation/ai/agentic-ui-generator/prompt-library">https://www.telerik.com/blazor-ui/documentation/ai/agentic-ui-generator/prompt-library</a></li><li>React: <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-tools/agentic-ui-generator/getting-started">https://www.telerik.com/kendo-react-ui/components/ai-tools/agentic-ui-generator/getting-started</a></li><li>Angular: <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/agentic-ui-generator/prompt-library">https://www.telerik.com/kendo-angular-ui/components/ai-tools/agentic-ui-generator/prompt-library</a></li></ul><h4 id="syncfusion-agentic-ui-builder-prompt-libraries">Syncfusion Agentic UI Builder Prompt Libraries</h4><p>Yes! Prompt libraries are included for the Syncfusion Agentic UI Builder tools:</p><ul><li>Blazor: <a target="_blank" href="https://blazor.syncfusion.com/documentation/mcp-server/agentic-ui-builder/prompt-library">https://blazor.syncfusion.com/documentation/mcp-server/agentic-ui-builder/prompt-library</a></li><li>React: <a target="_blank" href="https://ej2.syncfusion.com/react/documentation/mcp-server/agentic-ui-builder/prompt-library">https://ej2.syncfusion.com/react/documentation/mcp-server/agentic-ui-builder/prompt-library</a></li><li>Angular: <a target="_blank" href="https://ej2.syncfusion.com/angular/documentation/mcp-server/agentic-ui-builder/prompt-library">https://ej2.syncfusion.com/angular/documentation/mcp-server/agentic-ui-builder/prompt-library</a></li></ul><img src="https://feeds.telerik.com/link/23055/17315935.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:8adaf186-7275-4dfe-8fbd-0e63950051ac</id>
    <title type="text">Build Accessible Components with Angular Aria</title>
    <summary type="text">A simple way to add accessibility to your Angular app is with Angular Aria, which gives you production-ready, WCAG-compliant directives. Take a look.</summary>
    <published>2026-04-01T19:25:26Z</published>
    <updated>2026-09-02T08:08:54Z</updated>
    <author>
      <name>Dany Paredes </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17311879/build-accessible-components-angular-aria"/>
    <content type="text"><![CDATA[<p><span class="featured">A simple way to add accessibility to your Angular app is with Angular Aria, which gives you production-ready, WCAG-compliant directives.</span></p><p>Building accessible components is one of those things we know we <em>should</em> do, but often skip because it feels overwhelming. We need to <a target="_blank" href="https://www.telerik.com/blogs/improving-navigation-accessibility-4-quick-tips">read about accessibility tips and tricks</a> and a lot of documentation.</p><p>You start with a simple dropdown menu, knowing you need to handle keyboard navigation, ARIA attributes, focus management and screen reader support. Before you know it, your &ldquo;simple&rdquo; component has 200 lines of accessibility code you&rsquo;re not even sure is correct. (Unless you&rsquo;re using the Progress Kendo UI for <a target="_blank" href="https://www.telerik.com/kendo-angular-ui">Angular library</a>, which has accessibility baked in for you. )</p><p>What if I told you there&rsquo;s a way to get the accessibility magic you need, regardless of component library, with full control over your styling with the magic of <a target="_blank" href="https://angular.dev/guide/aria/overview">Angular Aria</a>?</p><p>But what is Angular Aria? Let&rsquo;s make a small intro.</p><h2 id="what-is-angular-aria">What Is Angular Aria?</h2><p>Think of Angular Aria as a collection of accessibility superpowers for your components, but instead of manually implementing keyboard navigation, ARIA attributes and focus management, you import a directive, add it to your HTML and, boom, your component is accessible.</p><p>The Angular team built these directives following the <a target="_blank" href="https://www.w3.org/WAI/ARIA/apg/">W3C Accessibility Guidelines</a>, so you don&rsquo;t have to become an accessibility expert to build compliant components.</p><h2 id="hold-on-what-about-angular-material">Hold On, What About Angular Material?</h2><p>Great question! If you&rsquo;ve been using Angular for a while, you&rsquo;re probably thinking: <em>&ldquo;We already have <a target="_blank" href="https://material.angular.io/">Angular Material</a>. Why do we need another library?&rdquo;</em></p><p>Here are the key differences:</p><p>Angular Material gives you complete, prestyled components. They look great out of the box, but they come with Material Design opinions baked in. If you want a button that doesn&rsquo;t look like a Material button, you&rsquo;re going to fight the framework.</p><p>Angular Aria gives you headless directives&mdash;just the accessibility logic, zero styling. You get all the keyboard navigation, ARIA attributes and screen reader support, but you control every pixel of how it looks.</p><p>Think of it this way:</p><ul><li>Angular Material: It is plug and play, looks good, works immediately, but everyone has the same result. If you were building a physical doorway to your business, it would look like all other businesses, just with your business name on the sign.</li><li>Angular Aria: This tool is more like the ramp to your front door, enabling anyone to access the business entrance, while allowing you to choose the awning, the window display and the door color.</li></ul><p>So when should you use each one? We&rsquo;ll dive deeper into that later in the article, but here&rsquo;s the quick answer:</p><ul><li>Use <strong>Angular Material</strong> when you need to ship fast and Material Design works for you.</li><li>Use <strong>Angular Aria</strong> when you have custom design requirements and need full control.</li></ul><p>Remember, accessibility isn&rsquo;t optional anymore. It&rsquo;s a <a target="_blank" href="https://www.telerik.com/blogs/what-does-european-accessibility-act-mean-developers">legal requirement</a> in many countries, and, more importantly, it&rsquo;s the right thing to do.</p><p>But implementing accessibility correctly is <strong>hard</strong>. You need to know:</p><ul><li>Which ARIA attributes to use (and when)</li><li>How keyboard navigation should work for each pattern</li><li>How to manage focus properly</li><li>How screen readers interpret your markup</li></ul><p>Angular Aria handles this complexity for you. You focus on the HTML structure, CSS styling and business logic, and Angular Aria takes care of accessibility.</p><p>But, as always, the best way to learn is by building something. Let&rsquo;s do it!</p><h2 id="set-up-the-project">Set Up the Project</h2><p>First, create a new Angular application. In your terminal, run the following command (be sure to have Node.js installed).</p><pre class=" language-bash"><code class="prism  language-bash">npx @angular/cli@latest new angular-aria-demo
</code></pre><p>When CLI prompts stylesheet format, pick CSS.</p><pre class=" language-bash"><code class="prism  language-bash">  - **Which stylesheet <span class="token function">format</span> would you like to use?** &rarr; CSS
</code></pre><p>Now, navigate to your project and add Angular Aria:</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">cd</span> angular-aria-demo
<span class="token function">npm</span> <span class="token function">install</span> @angular/aria
</code></pre><p>That&rsquo;s it. We now have a fresh Angular project with Angular Aria installed. Let&rsquo;s build something accessible!</p><h2 id="building-an-accessible-toolbar">Building an Accessible Toolbar</h2><p>Let&rsquo;s build a text formatting toolbar, the kind you see in rich text editors. This is a perfect example because it looks simple but has surprising accessibility complexity.</p><p>Using the CLI, generate a new component editor-toolbar:</p><pre class=" language-bash"><code class="prism  language-bash">ng generate c components/editor-toolbar
</code></pre><p>Perfect! Open the component with your editor, and import <code>Toolbar</code>, <code>ToolbarWidget</code> and <code>ToolbarWidgetGroup</code> directives provided by <code>@angular/aria/toolbar</code>.</p><pre class=" language-typescript"><code class="prism  language-typescript">  <span class="token keyword">import</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
  <span class="token keyword">import</span> <span class="token punctuation">{</span> Toolbar<span class="token punctuation">,</span> ToolbarWidget<span class="token punctuation">,</span> ToolbarWidgetGroup <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/aria/toolbar'</span><span class="token punctuation">;</span>
  
  @<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    selector<span class="token punctuation">:</span> <span class="token string">'app-editor-toolbar'</span><span class="token punctuation">,</span>
    templateUrl<span class="token punctuation">:</span> <span class="token string">'./editor-toolbar.component.html'</span><span class="token punctuation">,</span>
    styleUrl<span class="token punctuation">:</span> <span class="token string">'./editor-toolbar.component.css'</span><span class="token punctuation">,</span>
    imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>Toolbar<span class="token punctuation">,</span> ToolbarWidget<span class="token punctuation">,</span> ToolbarWidgetGroup<span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">EditorToolbarComponent</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre><p>Now it&rsquo;s time to build the HTML structure. We create a div container with the directive <code>[ngToolbar]</code>, which works as the main container. We also need <code>ToolbarWidget</code> to use with individual buttons and <code>ToolbarWidgetGroup</code> for groups of related buttons.</p><p>In the following HTML, we use every directive with divs and button elements. Copy it and paste into the <code>editor-toolbar.html</code>.</p><pre class=" language-html"><code class="prism  language-html">  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">ngToolbar</span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Text Formatting Tools<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>group<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">ngToolbarWidget</span>
           <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>undo<span class="token punctuation">"</span></span>
           <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span>
           <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>undo<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     Undo
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">ngToolbarWidget</span>
           <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>redo<span class="token punctuation">"</span></span>
           <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span>
           <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>redo<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     Redo
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>separator<span class="token punctuation">"</span></span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>separator<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

 <span class="token comment">&lt;!-- Text formatting group --&gt;</span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>group<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">ngToolbarWidget</span>
           <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bold<span class="token punctuation">"</span></span>
           <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span>
           <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bold<span class="token punctuation">"</span></span>
           <span class="token attr-name">#bold</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ngToolbarWidget<span class="token punctuation">"</span></span>
           <span class="token attr-name">[aria-pressed]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bold.selected()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     Bold
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">ngToolbarWidget</span>
           <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>italic<span class="token punctuation">"</span></span>
           <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span>
           <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>italic<span class="token punctuation">"</span></span>
           <span class="token attr-name">#italic</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ngToolbarWidget<span class="token punctuation">"</span></span>
           <span class="token attr-name">[aria-pressed]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>italic.selected()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     Italic
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>separator<span class="token punctuation">"</span></span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>separator<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

 <span class="token comment">&lt;!-- Alignment group (radio buttons) --&gt;</span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">ngToolbarWidgetGroup</span>
      <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>radiogroup<span class="token punctuation">"</span></span>
      <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>group<span class="token punctuation">"</span></span>
      <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Text alignment options<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">ngToolbarWidget</span>
           <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span>
           <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span>
           <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>align left<span class="token punctuation">"</span></span>
           <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>align left<span class="token punctuation">"</span></span>
           <span class="token attr-name">#leftAlign</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ngToolbarWidget<span class="token punctuation">"</span></span>
           <span class="token attr-name">[aria-checked]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>leftAlign.selected()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     Left
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">ngToolbarWidget</span>
           <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span>
           <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span>
           <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>align center<span class="token punctuation">"</span></span>
           <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>align center<span class="token punctuation">"</span></span>
           <span class="token attr-name">#centerAlign</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ngToolbarWidget<span class="token punctuation">"</span></span>
           <span class="token attr-name">[aria-checked]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>centerAlign.selected()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     Center
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">ngToolbarWidget</span>
           <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span>
           <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span>
           <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>align right<span class="token punctuation">"</span></span>
           <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>align right<span class="token punctuation">"</span></span>
           <span class="token attr-name">#rightAlign</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ngToolbarWidget<span class="token punctuation">"</span></span>
           <span class="token attr-name">[aria-checked]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>rightAlign.selected()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     Right
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>The final step is adding some CSS styles to make it look nice. Open the editor-toolbar.css and paste the following style:</p><pre class=" language-css"><code class="prism  language-css">  <span class="token selector"><span class="token attribute">[ngToolbar]</span> </span><span class="token punctuation">{</span>
 <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
 <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token number">8</span>px<span class="token punctuation">;</span>
 <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token number">8</span>px<span class="token punctuation">;</span>
 <span class="token property">background</span><span class="token punctuation">:</span> <span class="token hexcode">#f5f5f5</span><span class="token punctuation">;</span>
 <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token number">4</span>px<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.group</span> </span><span class="token punctuation">{</span>
 <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
 <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token number">4</span>px<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.separator</span> </span><span class="token punctuation">{</span>
 <span class="token property">width</span><span class="token punctuation">:</span> <span class="token number">1</span>px<span class="token punctuation">;</span>
 <span class="token property">background</span><span class="token punctuation">:</span> <span class="token hexcode">#ddd</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">button </span><span class="token punctuation">{</span>
 <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token number">8</span>px <span class="token number">12</span>px<span class="token punctuation">;</span>
 <span class="token property">border</span><span class="token punctuation">:</span> <span class="token number">1</span>px solid <span class="token hexcode">#ddd</span><span class="token punctuation">;</span>
 <span class="token property">background</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
 <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token number">4</span>px<span class="token punctuation">;</span>
 <span class="token property">cursor</span><span class="token punctuation">:</span> pointer<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">button<span class="token attribute">[aria-pressed="true"]</span>,
button<span class="token attribute">[aria-checked="true"]</span> </span><span class="token punctuation">{</span>
 <span class="token property">background</span><span class="token punctuation">:</span> <span class="token hexcode">#007acc</span><span class="token punctuation">;</span>
 <span class="token property">color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Perfect, we just added HTML, CSS and Angular Aria directives. To test it, open the app.html and add <code>&lt;app-editor-toolbar&gt;&lt;/app-editor-toolbar&gt;</code>, save changes and run your app.</p><pre class=" language-bash"><code class="prism  language-bash">ng serve
Initial chunk files <span class="token operator">|</span> Names         <span class="token operator">|</span> Raw size
main.js             <span class="token operator">|</span> main          <span class="token operator">|</span> 10.50 kB <span class="token operator">|</span> 
styles.css          <span class="token operator">|</span> styles        <span class="token operator">|</span> 95 bytes <span class="token operator">|</span> 

                    <span class="token operator">|</span> Initial total <span class="token operator">|</span> 10.59 kB

Application bundle generation complete. <span class="token punctuation">[</span>0.641 seconds<span class="token punctuation">]</span> - 2026-01-25T10:16:33.843Z

Watch mode enabled. Watching <span class="token keyword">for</span> <span class="token function">file</span> changes<span class="token punctuation">..</span>.
NOTE: Raw <span class="token function">file</span> sizes <span class="token keyword">do</span> not reflect development server per-request transformations.
  ➜  Local:   http://localhost:4200/
  ➜  press h + enter to show <span class="token function">help</span>
</code></pre><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-03/keyboard-navigating-buttons.gif?sfvrsn=b37b8cd8_8" alt="User navigates buttons with keyboard arrow keys" /></p><p>Try to use your toolbar with your keyboard. You&rsquo;ll find it works, and we didn&rsquo;t have to write any code for keyboard navigation logic (like: Arrow keys, Home, End), focus management, ARIA role attributes, screen reader announcements or selection state management. All of that complexity? Gone.</p><p>The <code>ngToolbar</code>, <code>ngToolbarWidget</code> and <code>ngToolbarWidgetGroup</code> directives handle all of that automatically.</p><p>We now have a fully accessible toolbar that works with keyboard navigation and screen readers, and we only wrote the HTML structure and CSS.</p><p>Angular Aria provides directives for the most common interactive patterns, we can get components for search and selection (like Autocomplete, Listbox and Select), navigation and actions (Menu, Menubar and Toolbar like we just built), and content organization (Accordion, Tabs, Tree and Grid). Every directive comes with complete documentation, working examples and API references. You can see the <a target="_blank" href="https://angular.dev/guide/aria/overview#whats-included">full list of available components</a> in the official Angular Aria documentation.</p><h2 id="but-im-a-fan-of-angular-material">But I&rsquo;m a Fan of Angular Material</h2><p>Yes, I understand Angular Material has a long relationship with Angular devs. You can continue using Angular Material when you:</p><ol><li><strong>Need to ship fast</strong> &ndash; You&rsquo;re building an MVP or internal tool and don&rsquo;t want to spend time on custom styling.</li><li><strong>Like Material Design</strong> &ndash; You&rsquo;re OK with the Google Material Design aesthetic.</li><li><strong>Have limited design resources</strong> &ndash; Your team doesn&rsquo;t have dedicated designers.</li></ol><p>Remember, <a target="_blank" href="https://material.angular.io/">Angular Material</a> is amazing, but it comes with opinions about how things should look.</p><p>If you try to heavily customize Material components, you&rsquo;ll spend more time fighting the framework than building features. I&rsquo;ve been there&mdash;overriding Material styles with <code>::ng-deep</code> and <code>!important</code> until the CSS becomes unmaintainable.</p><p>And don&rsquo;t even get me started on theming. Creating a custom theme for Angular Material is&hellip; let&rsquo;s just say &ldquo;special.&rdquo; It&rsquo;s doable, but it&rsquo;s tricky and requires deep knowledge of Sass and Material&rsquo;s theming system. (If you&rsquo;re curious about the complexity, I wrote about it in <a target="_blank" href="https://www.telerik.com/blogs/theme-ui-frameworks-angular-part-2-custom-theme-angular-material">Theme UI Frameworks in Angular: Part 2 - Custom Theme for Angular Material</a>.)</p><p>Angular Aria solves this by giving you <strong>zero styles</strong>. You start with a blank canvas and build exactly what you need.</p><p>Remember for simple cases, native elements are already accessible when you use <code>&lt;button&gt;</code> for buttons, <code>&lt;input type="radio"&gt;</code> for radio buttons or <code>&lt;select&gt;</code> for simple dropdowns. But Angular Aria gives you a third option: <strong>headless accessible components</strong> that you can style however you want, we can meet accessibility requirements, maintain full design control and avoid reinventing the wheel.</p><h2 id="recap">Recap</h2><p>We learned that accessibility doesn&rsquo;t have to be overwhelming. Angular Aria gives you production-ready, WCAG-compliant directives that handle the complex parts.</p><p>We provide the HTML structure and CSS and Angular Aria provides the accessibility without pain!</p><h3 id="but-what-about-kendo-ui">But What About Kendo UI?</h3><p>Maybe you want to ship faster (really fast) and have complex scenarios with datalist, charts, schedulers and complex UI patterns. If you read this article and are thinking: <em>&ldquo;This is great, but I still have to write all the HTML and CSS myself. Why not just use a complete component library?&rdquo;</em> you&rsquo;re asking the right question.</p><p>Here&rsquo;s when Progress <strong>Kendo UI for Angular</strong> makes more sense than Angular Aria or Angular Material:</p><p><strong>Use Kendo UI when you want:</strong></p><ol><li><strong>Everything out of the box</strong> &ndash; Prebuilt components with professional styling, themes and accessibility already done</li><li><strong>Advanced features included</strong> &ndash; Things like data grids with sorting/filtering, charts, schedulers and complex UI patterns</li><li><strong>Consistent design system</strong> &ndash; A cohesive look across all components without writing custom CSS</li><li><strong>Enterprise-grade support</strong> &ndash; Professional support, regular updates and guaranteed compatibility</li><li><strong>Speed PLUS customization</strong> &ndash; You need to ship fast <em>and</em> need options to customize (you&rsquo;ll have five fully built theme options plus the ability to tweak those or create your own theme)</li></ol><p>There&rsquo;s no &ldquo;wrong&rdquo; choice&mdash;just different tools for different jobs.</p><p>If you&rsquo;re building internal tools or you like the Kendo UI design system, Kendo UI saves you weeks of work, and, honestly? I can build complex stuff (data grids, schedulers, charts) in minutes, making Kendo UI the right answer for me.</p><p>Plus, you can use the Kendo UI for <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/ai-assistant/getting-started">Angular AI Coding Assistant</a>, an MCP server that automatically scaffolds components for AI agents. Instead of manually writing Kendo UI components, your AI assistant can do it for you. </p><blockquote><p>Want to learn more? Check out my article: <a target="_blank" href="https://www.telerik.com/blogs/angular-kendo-ui-mcp-making-agents-work">
 Angular and Kendo UI MCP: Making Agents Work for You</a></p></blockquote><ul><li><a target="_blank" href="https://github.com/danywalls/angular-aria-example">Source code</a></li><li><a target="_blank" href="https://angular.dev/guide/aria/overview">Angular Aria Documentation</a></li></ul><img src="https://feeds.telerik.com/link/23055/17311879.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:3c8c4ee0-cf8c-4226-b0de-9aa709b3a16e</id>
    <title type="text">Top 3 Everyday Angular Tasks That MCP Servers Automate for You</title>
    <summary type="text">Scaffolding, creating UI from ideas and data, iterating and updating. These are things every Angular developer does, and here’s how MCP can help.</summary>
    <published>2026-03-24T21:04:24Z</published>
    <updated>2026-09-02T08:08:54Z</updated>
    <author>
      <name>Alyssa Nicoll </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17305464/top-3-everyday-angular-tasks-mcp-servers-automate"/>
    <content type="text"><![CDATA[<p><span class="featured">Scaffolding, creating UI from ideas and data, iterating and updating. These are things every Angular developer does, and here&rsquo;s how MCP can help. </span></p><p>Angular developers spend a lot of time on repetitive UI tasks like scaffolding components, wiring data into views and adjusting layouts. Or, at least they used to, before the age of AI.</p><p>Now, MCP-powered tools can automate much of that work&mdash;letting coding assistants generate Angular code and tools like Agentic UI Generator turn prompts or data into working UI so developers can move faster.</p><blockquote><p>&ldquo;AI made refactoring and handling technical debt much faster, allowing us to focus on market features. Validating ideas, creating POCs, and writing tests are also areas where we&rsquo;ve seen huge impact. The whole development lifecycle changed, and it opened the door for exploration and innovation.&rdquo;<br />&mdash; Progress Product Team Insight</p></blockquote><p><strong>Model Context Protocol (MCP)</strong> is a way for AI assistants to connect directly to tools and dev environments instead of generating code in isolation.</p><p>Without that connection, AI can only make suggestions based on patterns it has seen before. It doesn&rsquo;t know what Angular version you&rsquo;re using, what components exist in your UI library or what APIs are actually available in your project. (Unless your assistant is built into a full-blown IDE, like <a href="https://www.telerik.com/blogs/how-to-use-cursor-modern-angular" target="_blank">Cursor</a>.)</p><p>Often, with AI, the output might look correct, but developers end up fixing hallucinated APIs or rewriting scaffolding to make it fit their app. MCP closes that gap by giving AI access to real context&mdash;frameworks, component libraries, project structure and tooling. Instead of guessing what code might work, the assistant can generate output grounded in the tools you&rsquo;re actually using.</p><p>So if you love VS Code, for example, but Copilot just isn&rsquo;t cutting it for frontend AI-generated code, this is where MCP can fill the gap.</p><p>This is especially true for frontend work. Angular developers spend a lot of time on repetitive UI tasks like scaffolding components, wiring data into views and configuring layouts. MCP-powered tools can automate much of that groundwork. Coding assistants can generate valid Angular structures, and tools like Agentic UI Generator can turn prompts or data into working UI.</p><p>The result isn&rsquo;t magic code generation&mdash;it&rsquo;s a faster starting point. AI helps developers get moving, while humans still shape the final result.</p><h2 id="task-1-scaffolding-angular-components-faster">Task #1: Scaffolding Angular Components Faster</h2><p>Creating components is one of the most common tasks in Angular development. Even with Angular CLI, developers still need to generate the component, add inputs, wire services and start building the template.</p><p>If your coding assistant is connected to the Progress <strong><a target="_blank" href="https://www.telerik.com/angular-mcp-servers">Kendo UI for Angular MCP server</a></strong>, it understands the components available in your UI library and can generate valid Angular structures using them.</p><p>With an MCP-powered coding assistant, you can start with a simple prompt:</p><pre class=" language-javascript"><code class="prism  language-javascript">#kendo_component_assistant Create a ProductCard Angular component that displays a product image<span class="token punctuation">,</span>
name<span class="token punctuation">,</span> and price using Kendo UI components<span class="token punctuation">.</span>
</code></pre><p>The assistant can generate a working Angular component structure:</p><pre class=" language-javascript"><code class="prism  language-javascript">@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-product-card'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>KENDO_LAYOUT<span class="token punctuation">,</span> NgOptimizedImage<span class="token punctuation">]</span><span class="token punctuation">,</span>
  template<span class="token punctuation">:</span> `
    <span class="token operator">&lt;</span>kendo<span class="token operator">-</span>card <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"product-card"</span> width<span class="token operator">=</span><span class="token string">"100%"</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>img
        kendoCardMedia
        <span class="token punctuation">[</span>ngSrc<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"product().imageUrl"</span>
        <span class="token punctuation">[</span>width<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"product().imageWidth"</span>
        <span class="token punctuation">[</span>height<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"product().imageHeight"</span>
        <span class="token punctuation">[</span>alt<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"product().imageAlt"</span>
      <span class="token operator">/</span><span class="token operator">&gt;</span>

      <span class="token operator">&lt;</span>kendo<span class="token operator">-</span>card<span class="token operator">-</span>body<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>h3 kendoCardTitle<span class="token operator">&gt;</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">product</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>name <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>h3<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>p <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"product-price"</span> <span class="token punctuation">[</span>attr<span class="token punctuation">.</span>aria<span class="token operator">-</span>label<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"'Price: ' + formattedPrice()"</span><span class="token operator">&gt;</span>
          <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">formattedPrice</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span>
        <span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>kendo<span class="token operator">-</span>card<span class="token operator">-</span>body<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>kendo<span class="token operator">-</span>card<span class="token operator">&gt;</span>
    <span class="token operator">...</span>
</code></pre><p>Instead of starting from scratch, developers get a <strong>valid Angular starting point immediately</strong> and can focus on refining the UI.</p><h2 id="task-2-turning-data-into-ui">Task #2: Turning Data Into UI</h2><p>A large portion of frontend work isn&rsquo;t writing complex logic&mdash;it&rsquo;s translating data and ideas into working UI.</p><p>As devs, we are accustomed to taking API responses or product requirements and turn them into forms, dashboards or application layouts. That process usually starts with sketching the structure of the interface and then building the components to support it.</p><p>With the <strong><a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/agentic-ui-generator/getting-started">Angular Agentic UI Generator</a></strong>, you can start that process with a prompt instead.</p><p>Because the tool connects to your UI library through MCP, it understands the components available in your stack and can generate layouts using them. Instead of manually assembling the structure of the page, the generator produces a working Angular layout you can refine.</p><p>For example, you might start with a prompt like this:</p><blockquote><p>#kendo-ui-generator Create a responsive Workflow Composer app layout that includes: a left sidebar that only takes up 1/3 max of the UI for available workflow steps (this is essentially a column that is a list of individual cards/tasks), and main canvas area for building connected flows.</p></blockquote><p>From there, the generator produces a starting UI layout using Kendo UI for Angular components.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-03/workflow-composer.png?sfvrsn=7250b55a_2" alt="Workflow Composer shows steps for start, webhook trigger, output" /></p><h2 id="task-3-updating-and-iterating-on-ui">Task #3: Updating and Iterating on UI</h2><p>Building the first version of a UI is only the beginning. Most frontend work happens in the iteration phase&mdash;adjusting layouts, adding interactions and refining components as requirements evolve.</p><p>This is another area where MCP-connected assistants can help speed things up. Instead of manually digging through templates and wiring new behavior, developers can describe the change they want and let the assistant update the structure.</p><p>For this last task, I took our generated Workflow Composer app and added drag-and-drop support with a simple prompt:</p><blockquote><p>#kendo_ui_generator let&rsquo;s add drag and drop</p></blockquote><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-03/ui-generator-add-drag-drop.png?sfvrsn=29ecb3c0_2" alt="kendo_ui_generator let&#39;s add drag and drop" /></p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-03/drag-drop-workflow.gif?sfvrsn=a5876330_1" alt="Workflow Composer now has drag and drop. User adds steps to the workflow in seconds." /></p><p>Rather than rewriting the layout or manually integrating interaction logic, the assistant extends the generated UI and adds the new behavior.</p><p>One thing I&rsquo;ve noticed while experimenting with this workflow is that <strong>single task prompts tend to work best</strong>. Breaking changes into bite-sized requests often produces cleaner results when working with MCP-powered tools and Copilot.</p><h2 id="why-mcp-matters">Why MCP Matters</h2><p>AI coding tools are useful, but without access to your real development environment, they can only generate suggestions based on patterns they&rsquo;ve seen before.</p><p>MCP changes that by connecting AI assistants directly to the tools developers already use. Instead of guessing which components exist or how your project is structured, the assistant can interact with real frameworks, libraries and development workflows.</p><p>That connection is what makes tasks like generating Angular components, creating UI layouts or iterating on interfaces possible with simple prompts. Rather than starting from scratch each time, devs get a working starting point that fits their stack.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Angular and Kendo UI MCP: Making Agents Work for You</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Keep reading: See what&rsquo;s possible when your AI assistant can use your actual tools to perform work for you: The Kendo UI for <a target="_blank" href="https://www.telerik.com/blogs/angular-kendo-ui-mcp-making-agents-work">Angular AI Coding Assistant can connect with the Angular MCP Server</a> in a truly intelligent way.</p></div></div><hr class="u-mb3" /></aside><h2 id="conclusion">Conclusion</h2><p>Angular developers spend a lot of time on repetitive UI work&mdash;scaffolding components, turning data into layouts and iterating on interfaces as requirements evolve.</p><p>MCP-powered tools can help automate much of that groundwork. Coding assistants can generate valid Angular structures, and tools like the <strong>Angular Agentic UI Generator</strong> can turn prompts into working UI layouts that developers can refine and extend.</p><p>If you&rsquo;d like to try it yourself, you can install our MCP servers and learn how to get started with <strong>Coding Assistant</strong> and <strong>Agentic UI Generator</strong> in the documentation.</p><p> <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/installation">Explore the MCP setup guide in the docs.</a></p><img src="https://feeds.telerik.com/link/23055/17305464.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:83355cb1-6aa7-4e16-a1ad-a46f9c085158</id>
    <title type="text">Angular and Kendo UI MCP: Making Agents Work for You</title>
    <summary type="text">See what’s possible when your AI assistant can use your actual tools to perform work for you: The Kendo UI for Angular AI Coding Assistant can connect with the Angular MCP Server in a truly intelligent way.</summary>
    <published>2026-03-18T18:51:53Z</published>
    <updated>2026-09-02T08:08:54Z</updated>
    <author>
      <name>Dany Paredes </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17301664/angular-kendo-ui-mcp-making-agents-work"/>
    <content type="text"><![CDATA[<p><span class="featured">See what’s possible when your AI assistant can use your actual tools to perform work for you: The Kendo UI for Angular AI Coding Assistant can connect with the Angular MCP Server in a truly intelligent way.</span></p>
<p>Building modern Angular applications involves juggling multiple tasks: executing CLI commands, managing libraries, navigating documentation and, now, integrating AI tools.</p>
<p>The challenge? Most AI assistants provide generic code snippets but lack context about your specific project structure or the professional UI tools you use.</p>
<p>What if your AI assistant could do more than just suggest code? What if it could actually use your tools to perform the work for you? Imagine an agent that doesn’t just “talk” about Angular and Kendo UI documentation but actually applies official best practices directly to your codebase.</p>
<p>Today, we’re going to bridge that gap. We’ll connect your AI tools directly to your project to literally <strong>make Angular and Kendo UI work for you</strong>.</p>
<p>We’ll achieve this using <a target="_blank" href="https://angular.dev/ai/mcp">Angular MCP</a> and the Progress <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/ai-assistant/getting-started">Kendo UI for Angular AI Coding Assistant</a>.</p>
<h2 id="but-first-what-is-mcp">But First, What Is MCP?</h2>
<p>MCP stands for <strong>Model Context Protocol</strong>. Think of it as a standardized bridge that allows AI assistants to securely interact with your local tools and data.</p>
<p>Before MCP, interacting with an AI was like having a video call with a senior developer; they could offer great advice, but they couldn’t touch your keyboard. With MCP our reality changes, MCP brings a standard way for AI to connect with our source code; enabling it to execute commands, read files and understand the state of your project in real time and give full access and context to help us.</p>
<p>For a deeper dive into the concept, I recommend checking out <a target="_blank" href="https://www.telerik.com/blogs/promise-model-context-protocol">The Promise of Model Context Protocol</a>.</p>
<p>By combining <strong>Angular MCP</strong> for project management and the <strong>Kendo UI for Angular AI Coding Assistant</strong> for professional UI components, we can transform the development experience. We stop typing <code>ng generate</code> commands manually and stop switching context so we can see Kendo UI documentation inside our editor by following the Progress team’s recommended practices.</p>
<p>Let’s talk first about Angular MCP!</p>
<h2 id="part-1-angular-mcp-the-builder">Part 1: Angular MCP (The Builder)</h2>
<p>Think of <strong>Angular MCP</strong> as a direct line between your AI-powered editor (like Cursor or VS Code) and the Angular CLI.</p>
<p>Instead of switching to a terminal, you can simply ask your AI to create a new component called <code>user-profile</code>, add <code>@angular/material</code> to your project, or fix a build error and explain what happened.</p>
<p>We need to register the MCP server in your editor’s configuration. In <strong>Cursor</strong>, open your MCP settings (usually found via <code>Command + Shift + P</code> &gt; “Open MCP Settings”) and add the following:</p>
<pre class=" language-json"><code class="prism  language-json"><span class="token punctuation">{</span>
  <span class="token string">"servers"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"angular-cli"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"stdio"</span><span class="token punctuation">,</span>
      <span class="token string">"command"</span><span class="token punctuation">:</span> <span class="token string">"npx"</span><span class="token punctuation">,</span>
      <span class="token string">"args"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"-y"</span><span class="token punctuation">,</span> <span class="token string">"@angular/cli"</span><span class="token punctuation">,</span> <span class="token string">"mcp"</span><span class="token punctuation">]</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<blockquote>
<p><strong>Note for VS Code users</strong>: The configuration file is typically located at:</p>
<ul>
<li><strong>macOS/Linux</strong>: <code>~/.vscode/mcp.json</code></li>
</ul>
</blockquote>
<blockquote>
<p><strong>Cursor users</strong>: You can add this JSON to your MCP configuration by opening the Command Palette (Cmd/Ctrl + Shift + P) and searching for “MCP.” The configuration file is located under the Tools &amp; MCP section.</p>
</blockquote>
<p>Once added, restart your editor and verify it works by asking: <em>“Generate a new Angular service called <code>api-client</code>.”</em></p>
<p><strong>Checkpoint:</strong> Your agent can now manage your Angular project. But how do we handle the UI design?</p>
<blockquote>
<p>Learn more about the basics of getting started with <a target="_blank" href="https://www.telerik.com/blogs/how-to-use-cursor-modern-angular">Angular and Cursor</a>.</p>
</blockquote>
<h2 id="kendo-ui-ai-coding-assistant-the-designer">Kendo UI AI Coding Assistant (The Designer)</h2>
<p>Building professional dashboards usually involves navigating documentation and manually wiring up complex components. The <strong>Kendo UI for Angular AI Coding Assistant</strong> changes this by acting as a local Kendo UI expert that understands the entire library.</p>
<p>The <a target="_blank" href="https://www.npmjs.com/package/@progress/kendo-angular-mcp">Kendo UI for Angular MCP Server</a> runs with <code>npx</code> and uses your Progress Telerik license directly.</p>
<p>First, you need a <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/installation#license-key-setup">valid Telerik license</a>. If you don’t have one, you can start a free trial and you don’t need a credit card. Second, you need to add the configuration to your <code>mcp.json</code> file:</p>
<pre class=" language-json"><code class="prism  language-json"><span class="token punctuation">{</span>
  <span class="token string">"servers"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"kendo-angular-mcp-server"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"stdio"</span><span class="token punctuation">,</span>
      <span class="token string">"command"</span><span class="token punctuation">:</span> <span class="token string">"npx"</span><span class="token punctuation">,</span>
      <span class="token string">"args"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"-y"</span><span class="token punctuation">,</span> <span class="token string">"@progress/kendo-angular-mcp@latest"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token string">"env"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
        <span class="token string">"TELERIK_LICENSE"</span><span class="token punctuation">:</span> <span class="token string">"YOUR_LICENSE_KEY_HERE"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<blockquote>
<p><strong>Pro tip:</strong> If you have your license key set up globally on your machine, you can omit the <code>env</code> section!</p>
</blockquote>
<p>Now your agent has the tools to build a responsive orders dashboard. Instead of writing hundreds of lines of code, you can simply prompt your agent using the <code>#kendo_angular_assistant</code> handle:</p>
<blockquote>
<p><em>“Use the #kendo_angular_assistant to build an OrdersDashboardComponent. I need a responsive layout with a sidebar, and a Kendo Grid in the main content area showing ID, Customer, Date, Status and Total. Add a “New Order” button in a toolbar above the grid and use the Kendo Default theme.”</em></p>
</blockquote>
<p>The agent follows three steps. It analyzes your request to see which Kendo UI components you need. Then, it generates clean and typed code for TypeScript and HTML using Kendo UI standards. Finally, it implements the code in your files and helps you with the modules.</p>
<p>Need to iterate? Just ask for a refinement:</p>
<blockquote>
<p><em>“Awesome. Now update the grid to allow filtering by Status using a dropdown, and highlight ‘Pending’ orders in yellow.”</em></p>
</blockquote>
<p>The agent adapts the code instantly, following your specialized requirements.</p>
<h2 id="lets-see-it-in-action">Let’s See It in Action</h2>
<p>To start a new project, just run this command in your terminal:</p>
<pre class=" language-bash"><code class="prism  language-bash">ng new kendo-store
</code></pre>
<p>Now, configure your editor with both MCP servers. Here is a complete example of how your <code>mcp.json</code> should look. Don’t forget to add your Telerik license key:</p>
<pre class=" language-json"><code class="prism  language-json"><span class="token punctuation">{</span>
  <span class="token string">"servers"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"angular-cli"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"stdio"</span><span class="token punctuation">,</span>
      <span class="token string">"command"</span><span class="token punctuation">:</span> <span class="token string">"npx"</span><span class="token punctuation">,</span>
      <span class="token string">"args"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"-y"</span><span class="token punctuation">,</span> <span class="token string">"@angular/cli"</span><span class="token punctuation">,</span> <span class="token string">"mcp"</span><span class="token punctuation">]</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token string">"kendo-angular-mcp-server"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"stdio"</span><span class="token punctuation">,</span>
      <span class="token string">"command"</span><span class="token punctuation">:</span> <span class="token string">"npx"</span><span class="token punctuation">,</span>
      <span class="token string">"args"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"-y"</span><span class="token punctuation">,</span> <span class="token string">"@progress/kendo-angular-mcp@latest"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token string">"env"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
        <span class="token string">"TELERIK_LICENSE"</span><span class="token punctuation">:</span> <span class="token string">"YOUR_LICENSE_KEY_HERE"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Now, let’s play with our Cursor agent. We want it to do the tasks for us using these new MCP tools.</p>
<p>For example, ask it which tools are available. It must show Kendo (if you have configured Angular or other MCP). Then, just use a prompt mentioning <code>#kendo_angular_assistant</code> like:</p>
<blockquote>
<p>#kendo_angular_assistant Create a basic Grid component that displays employee data with columns for ID, Name, Position, and Salary. Include sorting and pagination functionality.</p>
</blockquote>
<p>Let’s see how Cursor works with Kendo UI for Angular MCP:</p>
<p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-03/cursor-angular-kendo-mcp.gif?sfvrsn=cabfeb0c_2" alt="Searching Cursor: What tools have you available? And then selecting Kendo UI for Angular via MCP server"></p>
<p>Maybe you’re wondering, “Do I need to remember every prompt?” Don’t worry, Progress Kendo UI provides a list of <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/ai-assistant/prompt-library">optimized prompts ready for use with the Kendo UI for Angular AI Coding Assistant</a>.</p>
<p>Now you are ready with prompts and MCP to give the agents the tools to work for you.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Honestly, we shouldn’t spend our time fighting with our tools. We need to make them work for us.</p>
<p>With <a target="_blank" href="https://angular.dev/ai/mcp">Angular MCP</a> handling the CLI work and the <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/ai-assistant/getting-started">Kendo AI Assistant</a> building the professional UI, you can finally focus on what really matters: solving problems and building your app. No more boring boilerplate or searching documentation for hours.</p>
<p>Stop copying and pasting code from ChatGPT, or leaving your agent to work without tools. Give your agents the tools they need to work better for you!</p>
<ul>
<li><a target="_blank" href="https://angular.dev/ai/mcp">Angular MCP Documentation</a></li>
<li><a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/ai-assistant/getting-started">Kendo UI for Angular AI Coding Assistant</a></li>
</ul>
<p>And remember: Kendo UI for Angular comes with a free trial. So, give it a try if you aren’t already using it.</p>
<p><a target="_blank" href="https://www.telerik.com/try/kendo-angular-ui" class="Btn">Try Kendo UI for Angular</a></p><img src="https://feeds.telerik.com/link/23055/17301664.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:bcaf5568-f230-4813-a975-4ad2d3fdfcf7</id>
    <title type="text">Guide to Creating an Angular-based Micro-frontend Application Using Native Federation</title>
    <summary type="text">Micro-frontends break a large frontend application into smaller, independent components. Here’s how to do this in Angular with Native Federation.</summary>
    <published>2026-03-10T20:09:00Z</published>
    <updated>2026-09-02T08:08:54Z</updated>
    <author>
      <name>Dhananjay Kumar </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17297038/guide-creating-angular-based-micro-frontend-application-native-federation"/>
    <content type="text"><![CDATA[<p><span class="featured">Micro-frontends break a large frontend application into smaller, independent components. Follow these steps to create a micro-frontend in Angular with Native Federation.</span></p><p>Micro-frontends are an architectural pattern that extends the concept of microservices to frontend development. It involves breaking a large frontend application into smaller, independent and deployable components.</p><p>In this article, we will learn how to implement a micro-frontend architecture using Native Federation. We will:</p><ul><li>Create one host application</li><li>Create two remote client applications</li><li>Load the remote applications dynamically in the host application using routing or dynamic component loading</li></ul><p>Let&rsquo;s begin by creating the remote applications.</p><h2 id="creating-remote-apps">Creating Remote Apps</h2><p>We can use the Angular CLI to scaffold the client application. Let&rsquo;s create a remote app using the CLI command below.</p><pre><code>ng new remote-app1
</code></pre><p>After successfully creating the project, configure the Angular application as a remote app in the micro-frontend (MFE) setup by running the schematic command shown below.</p><pre><code>ng add @angular-architects/native-federation --project remote-app1 --port 4201 --type remote
</code></pre><p>Make sure to pass your project name after the <code>--project</code> flag (in this case, <code>remote-app1</code>). The CLI will then prompt you to confirm. After that, it will run the schematics and configure the Angular project as a remote application.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-02/native-federation-package-install.png?sfvrsn=dbf55db4_2" alt="The package @angular-architects/native-federation@21.0.3 will be installed and executed. Would you like to proceed? (y/n) screenshot" /></p><p>After the installation completes successfully, you will see a new federation.config.js file added to the project.</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> withNativeFederation<span class="token punctuation">,</span> shareAll <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'@angular-architects/native-federation/config'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token function">withNativeFederation</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  name<span class="token punctuation">:</span> <span class="token string">'remote-app2'</span><span class="token punctuation">,</span>


  exposes<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">'./Component'</span><span class="token punctuation">:</span> <span class="token string">'./src/app/app.ts'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  shared<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span><span class="token function">shareAll</span><span class="token punctuation">(</span><span class="token punctuation">{</span> singleton<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> strictVersion<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> requiredVersion<span class="token punctuation">:</span> <span class="token string">'auto'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  skip<span class="token punctuation">:</span> <span class="token punctuation">[</span>
    <span class="token string">'rxjs/ajax'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/fetch'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/testing'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/webSocket'</span><span class="token punctuation">,</span>
    <span class="token comment">// Add further packages you don't need at runtime</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>

  <span class="token comment">// Please read our FAQ about sharing libs:</span>
  <span class="token comment">// https://shorturl.at/jmzH0</span>

  features<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token comment">// New feature for more performance and avoiding</span>
    <span class="token comment">// issues with node libs. Comment this out to</span>
    <span class="token comment">// get the traditional behavior:</span>
    ignoreUnusedDeps<span class="token punctuation">:</span> <span class="token boolean">true</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Also, you will see changes in the angular.json file. Ideally, you should not change anything in this file except the <code>exposes</code> object. By default, it exposes the AppComponent, but you can also choose to expose routes if needed.</p><p>In the project, add home, product and invoice components. Then modify the route as shown below:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">export</span> <span class="token keyword">const</span> routes<span class="token punctuation">:</span> Routes <span class="token operator">=</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
        path<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
        component<span class="token punctuation">:</span> App<span class="token punctuation">,</span>
        children<span class="token punctuation">:</span> <span class="token punctuation">[</span>
            <span class="token punctuation">{</span> path<span class="token punctuation">:</span> <span class="token string">'home'</span><span class="token punctuation">,</span> component<span class="token punctuation">:</span> Home1 <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">{</span> path<span class="token punctuation">:</span> <span class="token string">'product'</span><span class="token punctuation">,</span> component<span class="token punctuation">:</span> Product <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">{</span> path<span class="token punctuation">:</span> <span class="token string">'invoice'</span><span class="token punctuation">,</span> component<span class="token punctuation">:</span> Invoice <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
</code></pre><p>On the AppComponent, add router-outlet and buttons to navigate as shown below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">&gt;</span></span>Client App<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>hr</span><span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">routerLink</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>home<span class="token punctuation">"</span></span> <span class="token attr-name">routerLinkActive</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>active<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Home<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">routerLink</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>product<span class="token punctuation">"</span></span> <span class="token attr-name">routerLinkActive</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>active<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Product<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">routerLink</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>invoice<span class="token punctuation">"</span></span> <span class="token attr-name">routerLinkActive</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>active<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Invoice<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>hr</span><span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-outlet</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-outlet</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>After that, expose the route by updating the exposes section in federation.config.js, as shown below.</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> withNativeFederation<span class="token punctuation">,</span> shareAll <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'@angular-architects/native-federation/config'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token function">withNativeFederation</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  name<span class="token punctuation">:</span> <span class="token string">'remote-app1'</span><span class="token punctuation">,</span>


  exposes<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">'./Routes'</span><span class="token punctuation">:</span> <span class="token string">'./src/app/app.routes'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  shared<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span><span class="token function">shareAll</span><span class="token punctuation">(</span><span class="token punctuation">{</span> singleton<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> strictVersion<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> requiredVersion<span class="token punctuation">:</span> <span class="token string">'auto'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  skip<span class="token punctuation">:</span> <span class="token punctuation">[</span>
    <span class="token string">'rxjs/ajax'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/fetch'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/testing'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/webSocket'</span><span class="token punctuation">,</span>
    <span class="token comment">// Add further packages you don't need at runtime</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>

  <span class="token comment">// Please read our FAQ about sharing libs:</span>
  <span class="token comment">// https://shorturl.at/jmzH0</span>

  features<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token comment">// New feature for more performance and avoiding</span>
    <span class="token comment">// issues with node libs. Comment this out to</span>
    <span class="token comment">// get the traditional behavior:</span>
    ignoreUnusedDeps<span class="token punctuation">:</span> <span class="token boolean">true</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In the same way, let&rsquo;s create one more remote application, but this time we won&rsquo;t add any routes to it. To create this application, run the following commands:</p><ul><li><code>ng new remote-app2</code></li><li><code>ng add @angular-architects/native-federation --project remote-app2 --port 4202 --type remote</code></li></ul><p>In this application, we will not configure any routes. This helps us understand how the host application can work with both an exposed <code>route</code> and an exposed <code>component</code>. So the federation.config.js of this application should look like:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> withNativeFederation<span class="token punctuation">,</span> shareAll <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'@angular-architects/native-federation/config'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token function">withNativeFederation</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  name<span class="token punctuation">:</span> <span class="token string">'remote-app2'</span><span class="token punctuation">,</span>


  exposes<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">'./Component'</span><span class="token punctuation">:</span> <span class="token string">'./src/app/app.ts'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  shared<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span><span class="token function">shareAll</span><span class="token punctuation">(</span><span class="token punctuation">{</span> singleton<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> strictVersion<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> requiredVersion<span class="token punctuation">:</span> <span class="token string">'auto'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  skip<span class="token punctuation">:</span> <span class="token punctuation">[</span>
    <span class="token string">'rxjs/ajax'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/fetch'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/testing'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/webSocket'</span><span class="token punctuation">,</span>
    <span class="token comment">// Add further packages you don't need at runtime</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>

  <span class="token comment">// Please read our FAQ about sharing libs:</span>
  <span class="token comment">// https://shorturl.at/jmzH0</span>

  features<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token comment">// New feature for more performance and avoiding</span>
    <span class="token comment">// issues with node libs. Comment this out to</span>
    <span class="token comment">// get the traditional behavior:</span>
    ignoreUnusedDeps<span class="token punctuation">:</span> <span class="token boolean">true</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>So far, we have configured two client applications, and you should be able to run them independently on ports <strong>4201</strong> and <strong>4202</strong>. In this way, you can create any number of client applications and set up independent deployment pipelines for each of them.</p><h2>Creating Host App</h2><p>Let&rsquo;s create a host app using the Angular CLI command:</p><pre><code>ng new host-app 
</code></pre><p>After scaffolding the application, use the following schematic command to configure it as the host application.</p><pre><code>ng add @angular-architects/native-federation --project host-app --port 4200 --type dynamic-host
</code></pre><p>After the installation completes successfully:</p><ul><li>A new federation.config.js file is added to the project.</li><li>The federation.manifest.json file is added to the public folder.</li><li>The main.ts file is updated.</li><li>The angular.json file is updated.</li></ul><p>The updated main.ts should look like this:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> initFederation <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular-architects/native-federation'</span><span class="token punctuation">;</span>

<span class="token function">initFederation</span><span class="token punctuation">(</span><span class="token string">'federation.manifest.json'</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>_ <span class="token operator">=&gt;</span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">'./bootstrap'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>You can also see the corresponding changes reflected in the angular.json file build and serve section, as shown below.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2026/2026-02/angular-json-file-build-serve.png?sfvrsn=b84fdaab_2" alt="angular.json file build and serve section" /></p><h2>Loading Remote Applications Dynamically</h2><p>Ideally, you should not make any changes to the scaffolded configuration, including the federation.config.ts file. The only file you need to update is federation.manifest.json, where you add the client application information.</p><pre class=" language-json"><code class="prism  language-json"><span class="token punctuation">{</span>
    <span class="token string">"client1"</span><span class="token punctuation">:</span> <span class="token string">"http://localhost:4201/remoteEntry.json"</span><span class="token punctuation">,</span>
    <span class="token string">"client2"</span><span class="token punctuation">:</span> <span class="token string">"http://localhost:4202/remoteEntry.json"</span>
<span class="token punctuation">}</span>
</code></pre><p>Here, <code>client1</code> and <code>client2</code> correspond to the two remote applications. You can choose any names you like, but make sure to use the same names when configuring the routes in the host application.</p><p>In the host application, you can create routes corresponding to the remote apps as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">const</span> routes<span class="token punctuation">:</span> Routes <span class="token operator">=</span> <span class="token punctuation">[</span>
<span class="token punctuation">{</span>
   path<span class="token punctuation">:</span><span class="token string">'home'</span><span class="token punctuation">,</span>
   component<span class="token punctuation">:</span>Home
<span class="token punctuation">}</span><span class="token punctuation">,</span>
 <span class="token punctuation">{</span>
    path<span class="token punctuation">:</span> <span class="token string">'client1'</span><span class="token punctuation">,</span>
    loadChildren<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
      <span class="token function">loadRemoteModule</span><span class="token punctuation">(</span><span class="token string">'client1'</span><span class="token punctuation">,</span> <span class="token string">'./Routes'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span>m<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> m<span class="token punctuation">.</span>routes<span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
   <span class="token punctuation">{</span>
    path<span class="token punctuation">:</span> <span class="token string">'client2'</span><span class="token punctuation">,</span>
    loadComponent<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
      <span class="token function">loadRemoteModule</span><span class="token punctuation">(</span><span class="token string">'client2'</span><span class="token punctuation">,</span> <span class="token string">'./Component'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span>m<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> m<span class="token punctuation">.</span>App<span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> path<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span> redirectTo<span class="token punctuation">:</span> <span class="token string">'home'</span><span class="token punctuation">,</span> pathMatch<span class="token punctuation">:</span> <span class="token string">'full'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>

<span class="token punctuation">]</span><span class="token punctuation">;</span>
</code></pre><p>Next, add the router-outlet and the navigation links to move between the different remote applications, as shown below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">&gt;</span></span>MFE APP<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>hr</span><span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">routerLink</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/home<span class="token punctuation">"</span></span> <span class="token attr-name">routerLinkActive</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>active<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Home<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">routerLink</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/client1<span class="token punctuation">"</span></span> <span class="token attr-name">routerLinkActive</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>active<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Client1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">routerLink</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/client2<span class="token punctuation">"</span></span> <span class="token attr-name">routerLinkActive</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>active<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Client2<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>hr</span><span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-outlet</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-outlet</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Now, when you navigate to <code>client1</code>, the first remote application loads. Similarly, when you navigate to <code>client2</code>, the second remote application loads.</p><p>If you want to load applications side by side without navigating to different URLs, you can achieve this by using Angular&rsquo;s dynamic component loading feature.</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token function">ViewChild</span><span class="token punctuation">(</span><span class="token string">'vcHostClient1'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> read<span class="token punctuation">:</span> ViewContainerRef<span class="token punctuation">,</span> <span class="token keyword">static</span><span class="token punctuation">:</span> <span class="token keyword">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> vcHostClient1<span class="token operator">!</span><span class="token punctuation">:</span> ViewContainerRef<span class="token punctuation">;</span>

   @<span class="token function">ViewChild</span><span class="token punctuation">(</span><span class="token string">'vcHostClient2'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> read<span class="token punctuation">:</span> ViewContainerRef<span class="token punctuation">,</span> <span class="token keyword">static</span><span class="token punctuation">:</span> <span class="token keyword">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> vcHostClient2<span class="token operator">!</span><span class="token punctuation">:</span> ViewContainerRef<span class="token punctuation">;</span>

  <span class="token keyword">async</span> <span class="token function">loadCient1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>

     <span class="token keyword">const</span> <span class="token punctuation">{</span>App<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">loadRemoteModule</span><span class="token punctuation">(</span><span class="token string">'client1'</span><span class="token punctuation">,</span><span class="token string">'./Component'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>App<span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token keyword">this</span><span class="token punctuation">.</span>vcHostClient1<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token keyword">this</span><span class="token punctuation">.</span>vcHostClient1<span class="token punctuation">.</span><span class="token function">createComponent</span><span class="token punctuation">(</span>App<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">async</span> <span class="token function">loadClient2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">const</span> <span class="token punctuation">{</span>App<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">loadRemoteModule</span><span class="token punctuation">(</span><span class="token string">'client2'</span><span class="token punctuation">,</span><span class="token string">'./Component'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>App<span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token keyword">this</span><span class="token punctuation">.</span>vcHostClient2<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token keyword">this</span><span class="token punctuation">.</span>vcHostClient2<span class="token punctuation">.</span><span class="token function">createComponent</span><span class="token punctuation">(</span>App<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre><p>And on the template, create ng-template to load as shown below:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loadCient1()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Load Client 1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loadClient2()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Load Client 2<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ng-template</span> <span class="token attr-name">#vcHostClient1</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ng-template</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ng-template</span> <span class="token attr-name">#vcHostClient2</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ng-template</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>So that's how you can load remote apps in different ways.</p><h2 id="summary">Summary</h2><p>In this article, we learned step by step how to build a micro-frontend application using Native Federation. I hope you found it helpful&mdash;thanks for reading!</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">How to Use Cursor with Modern Angular</h4></div><div class="col-8"><p class="u-fs16 u-mb0">This practical guide teaches you <a target="_blank" href="https://www.telerik.com/blogs/how-to-use-cursor-modern-angular">how to set up Cursor in Angular 21</a>.</p></div></div></aside><img src="https://feeds.telerik.com/link/23055/17297038.gif" height="1" width="1"/>]]></content>
  </entry>
</feed>
