<?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-blazor-61850150254c2.jpg</logo>
  <title type="text">Telerik Blogs | Web | Blazor</title>
  <subtitle type="text">The official blog of Progress Telerik - expert articles and tutorials for developers.</subtitle>
  <id>uuid:b58c0d09-9118-474d-9673-b5c5c2b82efa;id=5956</id>
  <updated>2026-06-14T09:54:16Z</updated>
  <link rel="alternate" href="https://www.telerik.com/"/>
  <link rel="self" type="application/atom+xml" href="https://feeds.telerik.com/blogs/web-blazor"/>
  <entry>
    <id>urn:uuid:fc4f18d8-9f5a-4741-bfdd-7844b4bdd7e0</id>
    <title type="text">Exploring the SLNX Solution File Format</title>
    <summary type="text">SLNX files are here! In this post, we'll talk about what this format is, why it exists, what it gets right and where you might get tripped up.</summary>
    <published>2026-06-11T19:09:21Z</published>
    <updated>2026-06-14T09:54:16Z</updated>
    <author>
      <name>Dave Brock </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23050/17359642/exploring-slnx-solution-file-format"/>
    <content type="text"><![CDATA[<p><span class="featured">SLNX files are here! In this post, we'll talk about what this format is, why it exists, what it gets right and where you might get tripped up.</span></p><p>If you&rsquo;ve worked with .NET for any length of time, you&rsquo;ve made peace with the <code>.sln</code> file. Not because it&rsquo;s good (it isn&rsquo;t) but because it&rsquo;s the format we have. It&rsquo;s verbose, GUID-laden and a reliable source of merge conflicts on Friday afternoons. It&rsquo;s the format we tolerate, not the one we&rsquo;d choose.</p><p>The good news is there&rsquo;s a new format in town. The <code>.slnx</code> format is Microsoft&rsquo;s XML-based replacement for the venerable <code>.sln</code> file, and it has been steadily gaining first-class support across Visual Studio, the .NET CLI, MSBuild and Rider over the last year. As of <a target="_blank" href="https://devblogs.microsoft.com/dotnet/introducing-slnx-support-dotnet-cli/">.NET 9.0.200</a> and <a target="_blank" href="https://devblogs.microsoft.com/visualstudio/new-simpler-solution-file-format/">Visual Studio 17.13+</a>, you can use it for real projects without crossing your fingers. And <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/10.0/dotnet-new-sln-slnx-default">as of .NET 10</a>, <code>dotnet new sln</code> defaults to <code>.slnx</code>.</p><p>In this post, let&rsquo;s talk about what <code>.slnx</code> is, why it exists, what it gets right and where you might get tripped up.</p><h2 id="a-quick-sln-retrospective">A Quick SLN Retrospective</h2><p>To appreciate why we&rsquo;re getting a new format, let&rsquo;s remember what we&rsquo;ve been working with. Here&rsquo;s a typical fragment of an <code>.sln</code> file.</p><pre><code>Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.10.34804.81
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyApi", "MyApi\MyApi.csproj", "{F95781B3-A973-4D19-9585-974DA143E6A1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8FC526EA-218B-4615-8410-4E1850611F38}"
ProjectSection(SolutionItems) = preProject
Directory.Build.props = Directory.Build.props
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F95781B3-A973-4D19-9585-974DA143E6A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F95781B3-A973-4D19-9585-974DA143E6A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F95781B3-A973-4D19-9585-974DA143E6A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F95781B3-A973-4D19-9585-974DA143E6A1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
</code></pre><p>Oof. The SLN format is a custom Microsoft format that has some weird quirks. Every project gets a GUID. Solution folders are themselves projects with their own GUIDs. Configuration combinations even get cross-multiplied so a four-project solution with two configurations and two platforms produces <em>16 lines</em> of nearly identical setup.</p><p>The pain points are well known to us all. If even two developers add a project at the same time, both edit <code>GlobalSection(ProjectConfigurationPlatforms)</code>, and Git throws its hands up.</p><p>GUIDs, bless their hearts, are not for human eyes. It&rsquo;s a nightmare trying to figure out which project owns which configuration block. And outside of Visual Studio, generating or modifying <code>.sln</code> files reliably often requires <a target="_blank" href="https://microsoft.github.io/slngen/">a tool like <code>slngen</code></a> because no one wants to write the parser themselves.</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">Visual Studio 2026, 6 Months Later</h4></div><div class="col-8"><p class="u-fs16 u-mb0">See what&rsquo;s really behind the <a target="_blank" href="https://www.telerik.com/blogs/visual-studio-2026-6-months-later">Visual Studio 2026 updates</a> and improvements, such as performance, GitHub Copilot, Hot Reload and more.
.</p></div></div><hr class="u-mb3" /></aside><p>This is what the <code>.slnx</code> tries to fix.</p><h2 id="looking-inside-the-.slnx">Looking Inside the .slnx</h2><p>Here&rsquo;s the same project, but expressed as <code>.slnx</code>.</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Solution</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Folder</span> <span class="token attr-name">Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/Solution Items/<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>File</span> <span class="token attr-name">Path</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Directory.Build.props<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>Folder</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Project</span> <span class="token attr-name">Path</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>MyApi/MyApi.csproj<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>Solution</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Notice how we have no GUIDs, no cross-multiplied configuration table and no <code>EndGlobalSection</code> markers. Even a developer who is foreign to the <code>.slnx</code> format can read it and immediately understand it.</p><p>Expanding a little, here&rsquo;s an example from a layered solution.</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Solution</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Folder</span> <span class="token attr-name">Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/Solution Items/<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>File</span> <span class="token attr-name">Path</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>.editorconfig<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>File</span> <span class="token attr-name">Path</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Directory.Build.props<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>File</span> <span class="token attr-name">Path</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Directory.Packages.props<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>Folder</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Folder</span> <span class="token attr-name">Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/src/<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>Project</span> <span class="token attr-name">Path</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>src/Application/Application.csproj<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>Project</span> <span class="token attr-name">Path</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>src/Domain/Domain.csproj<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>Project</span> <span class="token attr-name">Path</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>src/Infrastructure/Infrastructure.csproj<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>Project</span> <span class="token attr-name">Path</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>src/Web.Api/Web.Api.csproj<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>Folder</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Folder</span> <span class="token attr-name">Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/tests/<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>Project</span> <span class="token attr-name">Path</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>tests/UnitTests/UnitTests.csproj<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>Project</span> <span class="token attr-name">Path</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>tests/IntegrationTests/IntegrationTests.csproj<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>Folder</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Solution</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>If you compare this to the equivalent <code>.sln</code>, you&rsquo;re looking at maybe a third of the lines, with none of the GUID overhead. If you need to override configurations for a specific project (like, say your test project shouldn&rsquo;t build in Release mode) you can express that with a <code>Configurations</code> element on the project. In reality, most projects won&rsquo;t need it at all. If you do, you can review examples in <a target="_blank" href="https://github.com/microsoft/vs-solutionpersistence"><code>microsoft/vs-solutionpersistence</code></a> and its <a target="_blank" href="https://github.com/microsoft/vs-solutionpersistence/wiki/Samples">samples wiki</a>.</p><p>If the <code>.slnx</code> looks similar to a <code>.csproj</code>, that&rsquo;s intentional. Microsoft&rsquo;s reasoning is that XML is already the format the rest of MSBuild speaks, the team already had a parser for it, and features like comments and attributes are first-class citizens. A JSON or YAML format might have been trendier, but it would have forced the team to invent semantics for things <code>.csproj</code> already has solved problems for.</p><h2 id="migrating-existing-projects">Migrating Existing Projects</h2><p>Existing projects are a different conversation. Here&rsquo;s what you get by migrating, and how to do it cleanly.</p><ul><li><strong>Merge conflicts are more manageable.</strong> Because there are no GUIDs that change every time you touch a project, the diffs you see in PRs are meaningful. If you add a project, you see one line added. Move a project to a different folder, and you see the path change. Nobody has to play GUID detective.</li><li><strong>You can reasonably edit by hand.</strong> You&rsquo;ll never want to hand-edit a <code>.sln</code> unless it&rsquo;s an emergency. With <code>.slnx</code>, opening it in your editor of choice is perfectly reasonable. I&rsquo;ve fixed broken solution layouts in a text editor faster than Visual Studio would have let me click through the dialogs.</li><li><strong>Tooling has standardized what a solution is.</strong> Microsoft has open-sourced the parser as the <a target="_blank" href="https://www.nuget.org/packages/Microsoft.VisualStudio.SolutionPersistence/">Microsoft.VisualStudio.SolutionPersistence NuGet package</a>. This means MSBuild, the .NET CLI and third-party tools are all reading the same file the same way.</li></ul><p>Based on the official <code>dotnet sln</code> reference, the <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-sln">actual conversion is one command</a>.</p><pre><code>dotnet sln migrate
</code></pre><p>If you run this in a directory with an <code>.sln</code> file, you&rsquo;ll get an <code>.slnx</code> file beside it. From Visual Studio, you can also use <strong>File -&gt; Save Solution As&hellip;</strong> and pick <strong>XML Solution File (.slnx)</strong> from the dropdown. Rider supports a similar flow.</p><p>You don&rsquo;t want to keep both files in the repository. The <code>dotnet sln</code> commands don&rsquo;t reliably pick the right one when you have both, and it&rsquo;s easy for the two to get out of sync as people add or remove projects. Pick when to cut over, delete the old file and move on. While there is <a target="_blank" href="https://github.com/edvilme/dotnet-sln-sync">a community tool</a> called <code>dotnet-sln-sync</code> that helps, that should only be used temporarily and not long term.</p><p>As you convert over, here&rsquo;s a quick checklist to avoid any headaches:</p><ul><li><strong>Verify your <code>global.json</code> allows the right SDK.</strong> You need at least .NET 9.0.200 for full CLI support. If your <code>global.json</code> pins to something older, the migrate command won&rsquo;t work.</li><li><strong>Check your CI build agents.</strong> If you&rsquo;re on self-hosted Azure DevOps agents, for example, confirm they&rsquo;re running an SDK new enough to handle <code>.slnx</code>.</li><li><strong>Audit your pipelines.</strong> Anywhere you have references directly to <code>.sln</code>, update the path. Wildcard references like <code>**/*.sln</code> will miss the new file. If you are using templates where you have a mix of <code>.sln</code> and <code>.slnx</code>, a pattern like <code>**/*.sln*</code> will be useful.</li><li><strong>Look out for dependent tools.</strong> Tools like <code>slngen</code> don&rsquo;t yet support <code>.slnx</code> at the time of this post (you can <a target="_blank" href="https://github.com/microsoft/slngen/issues/643">track the issue here</a>). If you&rsquo;re reliant on a tool outside of the Microsoft umbrella, check before you migrate.</li></ul><h2 id="some-rough-edges">Some Rough Edges</h2><p>The <code>.slnx</code> format is no longer &ldquo;preview&rdquo; in any practical sense, but the ecosystem around it is still catching up.</p><ul><li><strong>Visual Studio file association.</strong> Double-clicking a <code>.slnx</code> file doesn&rsquo;t open Visual Studio by default. You can fix this with a file association or just open it from inside the IDE.</li><li><strong>C# Dev Kit in VS Code.</strong> It works, but you may need to set <a target="_blank" href="https://devblogs.microsoft.com/dotnet/introducing-slnx-support-dotnet-cli/"><code>dotnet.defaultSolution</code></a> to the path of your <code>.slnx</code> if it isn&rsquo;t auto-detected.</li><li><strong>Globbing.</strong> You can&rsquo;t write <code>&lt;Project Path="src/**/*.csproj" /&gt;</code> and have it discover projects automatically. The team&rsquo;s reasoning, captured in the <a target="_blank" href="https://github.com/microsoft/vs-solutionpersistence/issues/61">globbing feature request</a>, is that globbing slows down solution loading on large repos because Visual Studio has to scan the file system before it can render anything. That makes sense, <em>but</em> I think plenty of us would happily trade a slower cold load for never having to add another project entry by hand.</li><li><strong>Third-party tools.</strong> Anything that parses <code>.sln</code> directly needs to update. Hopefully the open-source parser library accelerates that, but you&rsquo;ll find holdouts.</li></ul><p>None of these are dealbreakers for new projects. For older codebases with a lot of tooling baked in, it&rsquo;s worth doing a small pilot before flipping the whole repo.</p><h2 id="wrapping-up">Wrapping Up</h2><p>The <code>.slnx</code> format isn&rsquo;t a revolutionary feature. It doesn&rsquo;t change how you write code, it doesn&rsquo;t add new build capabilities, and it doesn&rsquo;t speed up your application. It is, however, one of those quality-of-life upgrades that quietly results in fewer merge conflicts, less time staring at GUIDs, less friction in your CI pipelines once they&rsquo;re set up.</p><p>If you&rsquo;re starting a new .NET solution, just use <code>.slnx</code> from day one. And with .NET 10, you&rsquo;ll get it without lifting a finger. If you&rsquo;re maintaining an existing <code>.sln</code> file, plan a migration when you have a slow week, audit your tooling and cut over cleanly. The format isn&rsquo;t going anywhere, and getting ahead of the transition is easier than waiting for some downstream tool to force your hand.</p><p>Thanks for reading, and happy coding!</p><h2 id="further-reading">Further Reading</h2><ul><li><a target="_blank" href="https://devblogs.microsoft.com/visualstudio/new-simpler-solution-file-format/">New, simpler solution file format</a></li><li><a target="_blank" href="https://devblogs.microsoft.com/dotnet/introducing-slnx-support-dotnet-cli/">Introducing support for SLNX in the .NET CLI</a></li><li><a target="_blank" href="https://github.com/microsoft/vs-solutionpersistence"><code>microsoft/vs-solutionpersistence</code></a></li><li><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-sln"><code>dotnet sln</code> command reference</a></li><li><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/10.0/dotnet-new-sln-slnx-default">.NET 10 breaking change: <code>dotnet new sln</code> defaults to SLNX</a></li></ul><img src="https://feeds.telerik.com/link/23050/17359642.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:f5808969-92f6-4e38-b801-f36a47627abf</id>
    <title type="text">Visual Studio 2026, 6 Months Later</title>
    <summary type="text">Throughout this post, we’ll discuss Visual Studio updates and improvements, such as performance, GitHub Copilot, Hot Reload and more.</summary>
    <published>2026-06-04T21:42:24Z</published>
    <updated>2026-06-14T09:54:16Z</updated>
    <author>
      <name>Dave Brock </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23050/17354316/visual-studio-2026-6-months-later"/>
    <content type="text"><![CDATA[<p><span class="featured">Throughout this post, we&rsquo;ll discuss Visual Studio updates and improvements, such as performance, GitHub Copilot, Hot Reload and more.</span></p><p>I remember exactly where I was when <a target="_blank" href="https://devblogs.microsoft.com/visualstudio/visual-studio-2026-is-here-faster-smarter-and-a-hit-with-early-adopters/">Visual Studio 2026 dropped</a> back in November: at my desk, watching the Microsoft launch event with one eye and refactoring an <code>IDataReader</code> implementation with the other.</p><p>The keynote was typical Microsoft. There was a lot of &ldquo;reimagining how developers work.&rdquo; There was, of course, a slide with the word &ldquo;intelligent&rdquo; on it at least eight times. And the word &ldquo;Copilot&rdquo; appeared on screen so many times I started to wonder if Microsoft&rsquo;s marketing team had been replaced by an infinite loop that just prints <code>Copilot</code> forever.</p><p>Then I installed the thing.</p><p>The first week with VS 2026 was the most disoriented I&rsquo;ve felt in a Visual Studio release since <a target="_blank" href="https://devblogs.microsoft.com/visualstudio/a-design-with-all-caps/">the menu bar went all-caps in 2012</a> and I spent a month reading angry forum threads about it.</p><p>In 2026, I was tripped up by the just-slightly different Solution Explorer, the Copilot panel that lives where my Test Explorer used to live, the general Copilot onslaught and the interesting design choices. I felt like everything on my desk had been moved slightly to the left.</p><p>That was temporary. As with most new technology, eventually things felt normal again. I was finding workflows that genuinely beat my old ones and I stopped noticing the cosmetic changes. So here&rsquo;s where I am six months later &hellip; same machine, same kind of solution I work in every day, just a different IDE around it.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/vs2026-overview.png?sfvrsn=4ef376fb_2" alt="" /><br /><span style="font-size:14px;">We meet again, old friend. At least the menu bar isn't in caps.</span></p><p>Six months in, I feel comfortable. Six months is long enough to live with the rough edges, and find what&rsquo;s genuinely useful. So I&rsquo;m here to share them with you.</p><p>As an aside: to keep my sanity intact, I&rsquo;m going to use the word &ldquo;Copilot&rdquo; only when I absolutely have to. Microsoft has decided that every feature in Visual Studio is now Copilot-something &hellip; Copilot Chat, Copilot Edits, Copilot Agent, Copilot Workspaces, GitHub Copilot, Copilot for Azure, Copilot for Pull Requests and so on. So when I say &ldquo;the agent&rdquo; or &ldquo;the AI thing in the sidebar,&rdquo; you&rsquo;ll know what I mean.</p><h2 id="the-performance-story-is-real">The Performance Story Is Real</h2><p>I&rsquo;ll lead with this, mostly because it was the thing I was most skeptical about. Every Visual Studio release for the past decade has touted &ldquo;X% faster solution load!&rdquo; and, to me, every Visual Studio release for the last decade has felt (roughly) the same speed once you test it with your beefy codebase.</p><p>VS 2026 is genuinely faster. Not &ldquo;marketing-faster&rdquo; &hellip; actually faster. The <a target="_blank" href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022/">64-bit-everywhere story that started with VS 2022</a> has matured into something that handles large solutions without the periodic &ldquo;please hold&rdquo; pauses we&rsquo;re all familiar with. In Microsoft&rsquo;s VS2026 launch post, they say they <a target="_blank" href="https://devblogs.microsoft.com/visualstudio/visual-studio-2026-is-here-faster-smarter-and-a-hit-with-early-adopters/">cut hangs by over 50%</a>.</p><p>The IntelliSense responsiveness is the part I notice most. Typing a <code>.</code> after an object now produces suggestions roughly when I expect them to appear. A low bar? Definitely, but previous versions frequently limboed under it.</p><h2 id="agent-mode-is-useful-when-you-pick-the-right-job">Agent Mode Is Useful, When You Pick the Right Job</h2><p>GitHub Copilot&rsquo;s <a target="_blank" href="https://learn.microsoft.com/en-us/visualstudio/ide/copilot-agent-mode?view=visualstudio">agent mode in Visual Studio 2026</a>&mdash;or, as Microsoft prefers, <em>GitHub Copilot Agent Mode powered by Copilot in Visual Studio with Copilot</em>&mdash;has improved tremendously since Visual Studio 2022. Six months in, I think it&rsquo;s genuinely useful, but for a specific set of tasks.</p><p>In my experience, it works well with scoped, well-defined refactors. If I want to ask: <em>Hey Copilot, add a new health check for this Cosmos container and follow the pattern in my existing health checks.</em> (Yes, I sometimes talk to Copilot like a home assistant.) Or: <em>Take my new controller and add the same logging pattern as the others in this project.</em> And, after discovering some methods in a codebase with 11 nested if statements: <em>Convert this <code>for</code> loop to a LINQ expression but keep it readable.</em> It&rsquo;s effective enough that I&rsquo;ve stopped writing this kind of code by hand.</p><p>In my experience, things get harder when the agent needs to understand why something exists. The agent will happily refactor a piece of code that only exists because of, say, a weird third-party integration constraint from 2018, and the resulting code will be cleaner, more maintainable &hellip; and broken in production. Did I actually break something in production? Not this time. But I would have.</p><p>To be fair to the agent, this is exactly where it needs context. It doesn&rsquo;t read minds (although it sure does try). Here&rsquo;s a pattern I&rsquo;ve leaned on.</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token comment">// AGENT NOTES:</span>
<span class="token comment">// - This service must remain synchronous; the upstream caller cannot</span>
<span class="token comment">//   be made async without a contract change.</span>
<span class="token comment">// - The string "PRIME" is required by the third-party integration. </span>
<span class="token comment">//   I don't like it but they won't change it. Do not "improve" it </span>
<span class="token comment">//   to PersonType.Prime.ToString().</span>
<span class="token comment">// - Cancellation tokens must be forwarded; do NOT pass `default`.</span>
</code></pre><p>When the agent has clear context like this, it really delivers. Below is the agent producing two new health check files plus a registration update in <code>Program.cs</code>, all from one prompt asking it to mirror an existing pattern. The result is a careful refactoring with the right substitutions swapped in. That&rsquo;s exactly the kind of work I&rsquo;m happy to hand off.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/gh-copilot-agent.png?sfvrsn=a2b5eefe_2" alt="" /><br /><span style="font-size:14px;">The agent panel and one of the two generated files. Three files changed, zero hand-written by me. (My team is thankful for the latter.)</span></p><p>This sounds like babysitting, and it is. Welcome to AI-driven development, my friends. The 10 seconds of setup saves me from a 10-minute cleanup later. When the prep is solid, the result is solid.</p><p>For more information on <a target="_blank" href="https://learn.microsoft.com/en-us/visualstudio/ide/copilot-chat-context?view=visualstudio#use-custom-instructions">custom instructions, check out the Microsoft documentation</a>.</p><h2 id="test-explorer-isnt-frustrating">Test Explorer Isn&rsquo;t Frustrating</h2><p>In my experience, the Test Explorer seems to be much improved in Visual Studio 2026. If I had to sum it up in previous versions, I&rsquo;d say &ldquo;it&rsquo;s fine&rdquo; &hellip; after all, do we ever get jazzed about tests? In previous releases, I kept saying &ldquo;it&rsquo;s fine&rdquo; until I had a few thousand tests, at which point it started getting opinionated about which tests to run.</p><p>The new version is faster, the filtering predictably works, and it doesn&rsquo;t lose track of which tests are running when you switch branches mid-execution. Try it yourself. Run your full test suite and watch the Test Explorer not embarrass itself. It&rsquo;s a small joy.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/test-explorer.png?sfvrsn=222a8ba_2" alt="" /><br /><span style="font-size:14px;">One of those things you don't notice until it stops getting in your way.</span></p><h2 id="better-git-integration">Better Git Integration</h2><p>Visual Studio&rsquo;s Git tooling has historically been one of the IDE&rsquo;s more underwhelming features. Until recently, my workflow was:</p><ol><li>Make code changes in Visual Studio.</li><li>Run Git commands in my terminal (or a third-party tool like GitHub Desktop)</li><li>Ignore the IDE&rsquo;s Git panel entirely.</li></ol><p>With VS 2026, I&rsquo;m finally doing real Git work inside the tool. The new staging interface is better. The conflict resolution UI is also better than it used to be. The &ldquo;please show me an actual diff and not a vague summary&rdquo; feature is good.</p><p>Now, it&rsquo;s no GitKraken and it doesn&rsquo;t try to be. But it&rsquo;s good enough that I no longer switch over to a terminal for routine operations, and that works for me.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/git-conflict.png?sfvrsn=62f8884a_2" alt="" /><br /><span style="font-size:14px;">Three-way merge view, in the IDE I'm already in. Rejoice!</span></p><h2 id="hot-reload-that-reloads-more-often">Hot Reload That Reloads More Often</h2><p>Hot Reload has been one of those features that worked on Friday afternoons if I said &ldquo;please work&rdquo; (especially for ASP.NET Core). Any other time, I&rsquo;d change a method body, save, watch the IDE think very hard about it, and then get: <em>&ldquo;Hot Reload was unable to apply your changes. Restart the application?&rdquo;</em></p><p>The &ldquo;hot&rdquo; in &ldquo;Hot Reload&rdquo; was <a target="_blank" href="https://www.reddit.com/r/dotnet/comments/1my662s/will_microsoft_ever_fix_hot_reload_in_net/">stretching the truth</a> at times (with the understanding that getting it right <a target="_blank" href="https://www.reddit.com/r/dotnet/comments/1my662s/comment/naac88s/?utm_source=share&amp;utm_medium=web3x&amp;utm_name=web3xcss&amp;utm_term=1&amp;utm_content=share_button">isn&rsquo;t as simple in .NET</a> as it is for languages like JavaScript).</p><p>With VS 2026, I now reach for it instinctively instead of cynically. Method-body edits in controllers, services and Razor pages just apply. You change a string in a controller, hit Save and see the change. You know, the way it was supposed to work in 2021. The way it kind of worked in 2023. The way it now actually works in 2026.</p><p>When Hot Reload can&rsquo;t apply a change (because the change requires a metadata update or you&rsquo;ve added a field or whatever the actual reason is), the IDE now tells me clearly why instead of vaguely throwing up its hands. That alone goes a long way. I know whether to keep iterating or to just restart the host.</p><h3 id="debugger-improvements-especially-with-async-traces">Debugger Improvements (Especially with Async Traces)</h3><p>Have you ever stared at an async stack trace and felt your soul leave your body? Just me?</p><p>Historically, when an exception bubbled up from somewhere deep in an <code>async</code>/<code>await</code> chain, the stack trace was a wall of <code>MoveNext</code> calls and state machine internals. It was tremendously useful if you wanted to learn about the C# compiler, but not great if you wanted to know which of your methods actually threw.</p><p>Things are looking better in Visual Studio 2026. The debugger now stitches together async call chains into something that reads like the call graph you actually wrote. The <code>MoveNext</code> noise is collapsed by default. The original calling method is shown as the parent frame and not buried six levels down. When an exception is thrown inside a <code>Task.WhenAll</code>, you can see which task threw without reverse-engineering the parallel structure.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/debugger.png?sfvrsn=53980e30_2" alt="" /><br /><span style="font-size:14px;">An async exception, with the actual call chain visible. No <code>MoveNext</code> translation required.</span></p><p>On top of that, conditional breakpoints feel faster to evaluate, and the tracepoints (where you can log a message without breaking) is a one-click affair instead of a buried right-click option.</p><p>Small wins. But debugging is the thing I do every day, and small wins on the thing you do every day add up fast.</p><h2 id="the-verdict">The Verdict</h2><p>Look, the Copilot stuff is genuinely impressive. The agent demos at the keynote were the kind of thing that makes you want to fire up the installer immediately. And after six months, I&rsquo;ll admit that I use it every day.</p><p>But Visual Studio 2026 is a genuine step forward for the boring reasons. The performance is real. The Test Explorer doesn&rsquo;t stress me out. The debugger provides stack traces a human can read. The agent mode handles the kind of work I&rsquo;d previously do by hand. Those are the wins that show up in my daily work, not the ones that show up in keynote demos.</p><p>If you&rsquo;re on Visual Studio 2022 and wondering whether to upgrade: yes. Ignore the marketing, and let the unglamorous improvements do their job. Six months later, you won&rsquo;t be excited about Visual Studio 2026 &hellip; and that&rsquo;s exactly the point. You&rsquo;ll just be working faster.</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">Extension Properties: C# 14&rsquo;s Game-Changing Feature for Cleaner Code</h4></div><div class="col-8"><p class="u-fs16 u-mb0">This post introduces <a target="_blank" href="https://www.telerik.com/blogs/extension-properties-csharp-14-game-changing-feature-cleaner-code">extension properties</a>, a new feature of C# 14 that allows you to use properties in your extension methods.</p></div></div></aside><img src="https://feeds.telerik.com/link/23050/17354316.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:54ada40d-ff98-496d-94ae-1dbc6613c6e0</id>
    <title type="text">Advanced Form Validation in Blazor 10</title>
    <summary type="text">These new validation features available in Blazor as of .NET 10 help manage forms with nested objects and lists, plus perform complex and cross-field validations.</summary>
    <published>2026-06-03T13:34:16Z</published>
    <updated>2026-06-14T09:54:16Z</updated>
    <author>
      <name>Héctor Pérez </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23050/17353268/advanced-form-validation-blazor-10"/>
    <content type="text"><![CDATA[<p><span class="featured">These new validation features available in Blazor as of .NET 10 help manage forms with nested objects and lists, plus perform complex and cross-field validations.</span></p><p>Form validation is essential when working with data in Blazor applications. Before .NET 10, if you wanted to perform validation of nested objects, you had to take a series of additional steps that could add complexity to your projects. In this article, we will examine the improvements and new features in .NET 10 to solve this problem through a practical exercise. Let&rsquo;s go!</p><h2 id="understanding-the-problem-of-nested-validations-before-.net-10">Understanding the Problem of Nested Validations Before .NET 10</h2><p>To see the problem when working with nested objects and their validation, let&rsquo;s create a sample Blazor project. For this demonstration, I am working with a project using the <strong>Blazor Web App</strong> template configured with <strong>Interactive Server</strong> rendering <strong>globally</strong>.</p><p>Immediately after creating the project, perform the <a target="_blank" href="https://www.telerik.com/blazor-ui/documentation/getting-started/web-app">installation and configuration steps for the Progress Telerik UI for Blazor controls</a>, as we will use them to quickly build modern interfaces.</p><h3 id="creating-models-in-the-application">Creating Models in the Application</h3><p>Suppose we are building an attendee registration application for a technical event. As a first step, I have defined a class <code>EventRegistration</code> with the following structure:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">EventRegistration</span>
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> Attendee Attendee <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">public</span> BillingAddress BillingAddress <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">public</span> List<span class="token operator">&lt;</span>SessionSelection<span class="token operator">&gt;</span> Sessions <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><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 punctuation">[</span><span class="token function">Range</span><span class="token punctuation">(</span><span class="token keyword">typeof</span><span class="token punctuation">(</span><span class="token keyword">bool</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"true"</span><span class="token punctuation">,</span> <span class="token string">"true"</span><span class="token punctuation">,</span> ErrorMessage <span class="token operator">=</span> <span class="token string">"You must accept the terms and conditions."</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token keyword">public</span> <span class="token keyword">bool</span> AcceptTerms <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>The model above has some nested objects, both single objects such as <code>Attendee</code> and a list of type <code>SessionSelection</code>. Likewise, there is a validation on the property <code>AcceptTerms</code> of type <code>Range</code>, which verifies that the value is <code>true</code>.</p><p>The model of a <code>Attendee</code> looks as follows:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Attendee</span>
<span class="token punctuation">{</span>
    <span class="token punctuation">[</span><span class="token function">Required</span><span class="token punctuation">(</span>ErrorMessage <span class="token operator">=</span> <span class="token string">"Full name is required."</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token punctuation">[</span><span class="token function">StringLength</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> ErrorMessage <span class="token operator">=</span> <span class="token string">"Name cannot exceed 100 characters."</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span><span class="token operator">?</span> FullName <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</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>ErrorMessage <span class="token operator">=</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">EmailAddress</span><span class="token punctuation">(</span>ErrorMessage <span class="token operator">=</span> <span class="token string">"Invalid email format."</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span><span class="token operator">?</span> Email <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</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>ErrorMessage <span class="token operator">=</span> <span class="token string">"Phone number is required."</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token punctuation">[</span><span class="token function">Phone</span><span class="token punctuation">(</span>ErrorMessage <span class="token operator">=</span> <span class="token string">"Invalid phone number format."</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span><span class="token operator">?</span> Phone <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</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>ErrorMessage <span class="token operator">=</span> <span class="token string">"Company name is required."</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span><span class="token operator">?</span> Company <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</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>ErrorMessage <span class="token operator">=</span> <span class="token string">"Job title is required."</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span><span class="token operator">?</span> JobTitle <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>The <code>Attendee</code> model has more validation annotations per property, which allow validating each attendee&rsquo;s information. The project also includes the <code>BillingAddress</code> model to store address information, also featuring validation attributes:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">BillingAddress</span>
<span class="token punctuation">{</span>
    <span class="token punctuation">[</span><span class="token function">Required</span><span class="token punctuation">(</span>ErrorMessage <span class="token operator">=</span> <span class="token string">"Street address is required."</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span><span class="token operator">?</span> Street <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</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>ErrorMessage <span class="token operator">=</span> <span class="token string">"City is required."</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span><span class="token operator">?</span> City <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</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>ErrorMessage <span class="token operator">=</span> <span class="token string">"State/Province is required."</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span><span class="token operator">?</span> State <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</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>ErrorMessage <span class="token operator">=</span> <span class="token string">"Postal code is required."</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span><span class="token operator">?</span> PostalCode <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</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>ErrorMessage <span class="token operator">=</span> <span class="token string">"Country is required."</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span><span class="token operator">?</span> Country <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Finally, the <code>SessionSelection</code> model defines the structure of each session selected by an attendee:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SessionSelection</span>
<span class="token punctuation">{</span>
    <span class="token punctuation">[</span><span class="token function">Required</span><span class="token punctuation">(</span>ErrorMessage <span class="token operator">=</span> <span class="token string">"Session name is required."</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span><span class="token operator">?</span> SessionName <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</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>ErrorMessage <span class="token operator">=</span> <span class="token string">"Preference level is required."</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span><span class="token operator">?</span> Preference <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>The complexity among the previous models will allow us to test the new validation features included in .NET 10.</p><h3 id="initializing-project-data-using-a-session-catalog-service">Initializing Project Data Using a Session Catalog Service</h3><p>To display mock data in the application, let&rsquo;s create a <code>SessionCatalog</code> service, where we&rsquo;ll define a list of sessions:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SessionCatalog</span>
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> List<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token operator">&gt;</span> <span class="token function">GetAvailableSessions</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span>
    <span class="token punctuation">[</span>
        <span class="token string">"Keynote: The Future of .NET"</span><span class="token punctuation">,</span>
        <span class="token string">"Workshop: Blazor Advanced Patterns"</span><span class="token punctuation">,</span>
        <span class="token string">"Talk: SignalR Real-Time Communication"</span><span class="token punctuation">,</span>
        <span class="token string">"Workshop: Minimal APIs Deep Dive"</span><span class="token punctuation">,</span>
        <span class="token string">"Talk: Cloud-Native .NET Applications"</span><span class="token punctuation">,</span>
        <span class="token string">"Workshop: AI Integration with .NET"</span>
    <span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> List<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token operator">&gt;</span> <span class="token function">GetPreferenceLevels</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span>
    <span class="token punctuation">[</span>
        <span class="token string">"High"</span><span class="token punctuation">,</span>
        <span class="token string">"Medium"</span><span class="token punctuation">,</span>
        <span class="token string">"Low"</span>
    <span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>We will register this service in <code>Program.cs</code> as follows:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">var</span> builder <span class="token operator">=</span> WebApplication<span class="token punctuation">.</span><span class="token function">CreateBuilder</span><span class="token punctuation">(</span>args<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>
builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method function">AddSingleton<span class="token punctuation">&lt;</span>SessionCatalog<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">var</span> app <span class="token operator">=</span> builder<span class="token punctuation">.</span><span class="token function">Build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><h3 id="creating-the-graphical-interface">Creating the Graphical Interface</h3><p>To perform various checks, let&rsquo;s create a graphical interface using the <code>TelerikForm</code> component. This will enable generating and customizing model-based forms and with many configuration parameters, making it a powerful and useful component for our example. The resulting code looks like this:</p><pre class=" language-xml"><code class="prism  language-xml">@page "/registration"
@rendermode InteractiveServer
@using FormValidationNET10.Models
@using FormValidationNET10.Services
@inject SessionCatalog SessionCatalog

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>PageTitle</span><span class="token punctuation">&gt;</span></span>Event Registration<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>PageTitle</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mb-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Event Registration<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>TelerikForm</span> <span class="token attr-name">EditContext</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>editContext<span class="token punctuation">"</span></span>
             <span class="token attr-name">OnValidSubmit</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>HandleValidSubmit<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>FormValidation</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>DataAnnotationsValidator</span> <span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikValidationSummary</span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>FormValidation</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>FormItems</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>FormItem</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Attendee.FullName<span class="token punctuation">"</span></span> <span class="token attr-name">LabelText</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Full 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>FormItem</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Attendee.Email<span class="token punctuation">"</span></span> <span class="token attr-name">LabelText</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 punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>FormItem</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Attendee.Phone<span class="token punctuation">"</span></span> <span class="token attr-name">LabelText</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Phone<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>FormItem</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Attendee.Company<span class="token punctuation">"</span></span> <span class="token attr-name">LabelText</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Company<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>FormItem</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Attendee.JobTitle<span class="token punctuation">"</span></span> <span class="token attr-name">LabelText</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Job Title<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>FormItem</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>BillingAddress.Street<span class="token punctuation">"</span></span> <span class="token attr-name">LabelText</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Street<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>FormItem</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>BillingAddress.City<span class="token punctuation">"</span></span> <span class="token attr-name">LabelText</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>City<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>FormItem</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>BillingAddress.State<span class="token punctuation">"</span></span> <span class="token attr-name">LabelText</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>State / Province<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>FormItem</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>BillingAddress.PostalCode<span class="token punctuation">"</span></span> <span class="token attr-name">LabelText</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Postal Code<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>FormItem</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>BillingAddress.Country<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>Template</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>country-editor<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>k-label k-form-label<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Country<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>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>k-form-field-wrap<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>TelerikDropDownList</span> <span class="token attr-name">@bind-Value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>registration.BillingAddress.Country<span class="token punctuation">"</span></span>
                                         <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@countries<span class="token punctuation">"</span></span>
                                         <span class="token attr-name">DefaultText</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Select a country...<span class="token punctuation">"</span></span>
                                         <span class="token attr-name">Id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>country-editor<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>TelerikValidationMessage</span> <span class="token attr-name">For</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@(() =&gt; registration.BillingAddress.Country)<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 tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Template</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>FormItem</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>FormItem</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>AcceptTerms<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>Template</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>k-form-field-wrap<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>TelerikCheckBox</span> <span class="token attr-name">@bind-Value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>registration.AcceptTerms<span class="token punctuation">"</span></span> <span class="token attr-name">Id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>acceptTerms<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 attr-name">for</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>acceptTerms<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>ms-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>I accept the terms and conditions<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>div</span><span class="token punctuation">&gt;</span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikValidationMessage</span> <span class="token attr-name">For</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@(() =&gt; registration.AcceptTerms)<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 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>Template</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>FormItem</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>FormItems</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>FormItemsTemplate</span> <span class="token attr-name">Context</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>formContext<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        @{
            var items = formContext.Items.OfType<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>IFormItem</span><span class="token punctuation">&gt;</span></span>().ToList();
        }

        <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>card shadow-sm mb-4<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>card-header bg-primary text-white<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>h5</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mb-0<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Attendee Information<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h5</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>card-body<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>row g-3<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>col-md-6<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                        &lt;TelerikFormItemRenderer Item="@(items.First(x =&gt; x.Field == "Attendee.FullName"))" /&gt;
                    <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>col-md-6<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                        &lt;TelerikFormItemRenderer Item="@(items.First(x =&gt; x.Field == "Attendee.Email"))" /&gt;
                    <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>col-md-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                        &lt;TelerikFormItemRenderer Item="@(items.First(x =&gt; x.Field == "Attendee.Phone"))" /&gt;
                    <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>col-md-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                        &lt;TelerikFormItemRenderer Item="@(items.First(x =&gt; x.Field == "Attendee.Company"))" /&gt;
                    <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>col-md-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                        &lt;TelerikFormItemRenderer Item="@(items.First(x =&gt; x.Field == "Attendee.JobTitle"))" /&gt;
                    <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>
            <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>

        <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>card shadow-sm mb-4<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>card-header bg-primary text-white<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>h5</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mb-0<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Billing Address<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h5</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>card-body<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>row g-3<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>col-12<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                        &lt;TelerikFormItemRenderer Item="@(items.First(x =&gt; x.Field == "BillingAddress.Street"))" /&gt;
                    <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>col-md-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                        &lt;TelerikFormItemRenderer Item="@(items.First(x =&gt; x.Field == "BillingAddress.City"))" /&gt;
                    <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>col-md-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                        &lt;TelerikFormItemRenderer Item="@(items.First(x =&gt; x.Field == "BillingAddress.State"))" /&gt;
                    <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>col-md-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                        &lt;TelerikFormItemRenderer Item="@(items.First(x =&gt; x.Field == "BillingAddress.PostalCode"))" /&gt;
                    <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>col-md-12<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                        &lt;TelerikFormItemRenderer Item="@(items.First(x =&gt; x.Field == "BillingAddress.Country"))" /&gt;
                    <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>
            <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>

        <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>card shadow-sm mb-4<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>card-header bg-primary text-white d-flex justify-content-between align-items-center<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>h5</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mb-0<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Session Selection<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h5</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikButton</span> <span class="token attr-name">OnClick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@AddSession<span class="token punctuation">"</span></span>
                               <span class="token attr-name">ThemeColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.Button.ThemeColor.Light<span class="token punctuation">"</span></span>
                               <span class="token attr-name">ButtonType</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ButtonType.Button<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                    + Add Session
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikButton</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>card-body<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                @if (registration.Sessions.Count == 0)
                {
                    <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>alert alert-info mb-0<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                        No sessions added yet. Click "Add Session" to select the sessions you'd like to attend.
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
                }
                else
                {
                    @for (int i = 0; i &lt; registration.Sessions.Count; i++)
                    {
                        var index = i;
                        <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>row g-3 mb-3 align-items-end<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>col-md-5<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 attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>k-label k-form-label<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Session<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>TelerikDropDownList</span> <span class="token attr-name">@bind-Value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>registration.Sessions[index].SessionName<span class="token punctuation">"</span></span>
                                                     <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@availableSessions<span class="token punctuation">"</span></span>
                                                     <span class="token attr-name">DefaultText</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Select a session...<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>TelerikValidationMessage</span> <span class="token attr-name">For</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@(() =&gt; registration.Sessions[index].SessionName)<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 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>col-md-4<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 attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>k-label k-form-label<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Preference<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>TelerikDropDownList</span> <span class="token attr-name">@bind-Value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>registration.Sessions[index].Preference<span class="token punctuation">"</span></span>
                                                     <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@preferenceLevels<span class="token punctuation">"</span></span>
                                                     <span class="token attr-name">DefaultText</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Select preference...<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>TelerikValidationMessage</span> <span class="token attr-name">For</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@(() =&gt; registration.Sessions[index].Preference)<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 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>col-md-3<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>TelerikButton</span> <span class="token attr-name">OnClick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@(() =&gt; RemoveSession(index))<span class="token punctuation">"</span></span>
                                               <span class="token attr-name">ThemeColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.Button.ThemeColor.Error<span class="token punctuation">"</span></span>
                                               <span class="token attr-name">ButtonType</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ButtonType.Button<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                                    Remove
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikButton</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>
                    }
                }
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikValidationMessage</span> <span class="token attr-name">For</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@(() =&gt; registration.Sessions)<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 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>card shadow-sm mb-4<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>card-body<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                &lt;TelerikFormItemRenderer Item="@(items.First(x =&gt; x.Field == "AcceptTerms"))" /&gt;
            <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>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>FormItemsTemplate</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>FormButtons</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikButton</span> <span class="token attr-name">ButtonType</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ButtonType.Submit<span class="token punctuation">"</span></span>
                       <span class="token attr-name">ThemeColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.Button.ThemeColor.Primary<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            Submit Registration
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikButton</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>FormButtons</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikForm</span><span class="token punctuation">&gt;</span></span>

@if (isSubmitted)
{
    <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>alert alert-success mt-4<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>h5</span><span class="token punctuation">&gt;</span></span>Registration Successful!<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h5</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>Thank you, <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>strong</span><span class="token punctuation">&gt;</span></span>@registration.Attendee.FullName<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</span><span class="token punctuation">&gt;</span></span>! Your registration for @registration.Sessions.Count session(s) has been submitted.<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 punctuation">&gt;</span></span>
}

@code {
    private EventRegistration registration = new();
    private EditContext editContext = default!;
    private List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">&gt;</span></span> availableSessions = [];
    private List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">&gt;</span></span> preferenceLevels = [];
    private List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">&gt;</span></span> countries = ["United States", "Canada", "Mexico", "United Kingdom", "Germany", "France", "Spain"];
    private bool isSubmitted;

    protected override void OnInitialized()
    {
        editContext = new EditContext(registration);
        
        availableSessions = SessionCatalog.GetAvailableSessions();
        preferenceLevels = SessionCatalog.GetPreferenceLevels();
    }

    private void AddSession()
    {
        registration.Sessions.Add(new SessionSelection());
    }

    private void RemoveSession(int index)
    {
        registration.Sessions.RemoveAt(index);
    }

    private void HandleValidSubmit(EditContext context)
    {
        isSubmitted = true;
    }
}
</code></pre><h3 id="validating-data-before-.net-10">Validating Data Before .NET 10</h3><p>Once we have all the pieces of the project, let&rsquo;s run it. Let&rsquo;s do a test by trying to submit the empty form:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/form-post-nested-objects-binding-before-net10.gif?sfvrsn=8b4e6fd5_2" alt="Form post showing nested object binding failures before .NET 10" /></p><p>In the previous image, you can see that when submitting the form the only error shown is the one indicating that the terms and conditions have not been accepted. However, although all models implement validations, no others are shown.</p><p>The reason behind this is that <code>DataAnnotationsValidator</code> in Blazor does not perform validation on nested objects or collections. This has been a known limitation in Blazor since its beginnings, which was addressed using custom recursive validators. Let&rsquo;s see how .NET 10 helps us solve this problem.</p><h2 id="validating-data-thanks-to-the-new-features-in-.net-10">Validating Data Thanks to the New Features in .NET 10</h2><p>To perform validation of nested objects and collections, the first step you must take is to add in <code>Program.cs</code> a call to the method <code>AddValidation()</code>:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">var</span> builder <span class="token operator">=</span> WebApplication<span class="token punctuation">.</span><span class="token function">CreateBuilder</span><span class="token punctuation">(</span>args<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>
builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token function">AddValidation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">var</span> app <span class="token operator">=</span> builder<span class="token punctuation">.</span><span class="token function">Build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The method <code>AddValidation()</code> registers the services required for the validation system to work.</p><p>The next step is to open the main model that contains the hierarchy of submodels and add the attribute <code>[ValidatableType]</code> to the class. In our example, the class is <code>EventRegistration</code>, which will look as follows after the modification:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token punctuation">[</span>ValidatableType<span class="token punctuation">]</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">EventRegistration</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 attribute <code>[ValidatableType]</code> tells the .NET source generator to generate validation logic for the class. Behind the scenes the following steps will be performed:</p><ol><li>All properties of the decorated class are inspected.</li><li>Nested objects are detected and the necessary code to recursively validate their validation annotations is generated.</li><li>Collections are detected and code is generated to iterate through each element, validating their validation annotations.</li></ol><p>After applying the previous changes, you will see that now, when submitting the form with empty fields, all errors are displayed correctly:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/form-validating-nested-objects-net10.gif?sfvrsn=60d57217_2" alt="Web form displaying nested object fields with validation" /></p><p>With these changes, we have correctly enabled full validation of nested objects and collections.</p><h3 id="implementing-cross-field-validation-using-ivalidatableobject">Implementing Cross-field Validation Using IValidatableObject</h3><p>So far we have been able to apply validation rules at the level of individual properties. However, it is common in complex applications to have rules that involve multiple properties or complex business logic. For these cases, .NET provides the interface <code>IValidatableObject</code>, which in version 10 integrates seamlessly with <code>[ValidatableType]</code>.</p><p>Let&rsquo;s perform a check of this type assuming this pair of business rules:</p><ul><li>The user must select at least one session.</li><li>Duplicate sessions are not allowed.</li></ul><p>The rules depend on the state of the collection <code>Sessions</code> as a whole. To make it work correctly, let&rsquo;s modify the class <code>EventRegistration</code> by adding the interface:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token punctuation">[</span>ValidatableType<span class="token punctuation">]</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">EventRegistration</span> <span class="token punctuation">:</span> IValidatableObject
<span class="token punctuation">{</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>

    <span class="token keyword">public</span> IEnumerable<span class="token operator">&lt;</span>ValidationResult<span class="token operator">&gt;</span> <span class="token function">Validate</span><span class="token punctuation">(</span>ValidationContext validationContext<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
    <span class="token comment">// 1.</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>Sessions<span class="token punctuation">.</span>Count <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">yield</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">ValidationResult</span><span class="token punctuation">(</span>
                <span class="token string">"You must select at least one session."</span><span class="token punctuation">,</span>
                <span class="token punctuation">[</span><span class="token function">nameof</span><span class="token punctuation">(</span>Sessions<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 comment">// 2.</span>
        <span class="token keyword">var</span> duplicates <span class="token operator">=</span> Sessions
            <span class="token punctuation">.</span><span class="token function">Where</span><span class="token punctuation">(</span>s <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token operator">!</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>s<span class="token punctuation">.</span>SessionName<span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">GroupBy</span><span class="token punctuation">(</span>s <span class="token operator">=</span><span class="token operator">&gt;</span> s<span class="token punctuation">.</span>SessionName<span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">Where</span><span class="token punctuation">(</span>g <span class="token operator">=</span><span class="token operator">&gt;</span> g<span class="token punctuation">.</span><span class="token function">Count</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">1</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">Select</span><span class="token punctuation">(</span>g <span class="token operator">=</span><span class="token operator">&gt;</span> g<span class="token punctuation">.</span>Key<span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">ToList</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>duplicates<span class="token punctuation">.</span>Count <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">yield</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">ValidationResult</span><span class="token punctuation">(</span>
                $<span class="token string">"Duplicate sessions are not allowed: {string.Join("</span><span class="token punctuation">,</span> <span class="token string">", duplicates)}"</span><span class="token punctuation">,</span>
                <span class="token punctuation">[</span><span class="token function">nameof</span><span class="token punctuation">(</span>Sessions<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 code above:</p><ol><li>We validate that at least one session is selected.</li><li>We look for duplicate sessions.</li></ol><p>In case of any error, we return an <code>ValidationResult</code> indicating the error. When running the application, we see the following result if no session is selected:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/validation-no-session-selected.png?sfvrsn=8e250e63_2" alt="Validation error shown for no session selected" /></p><p>Now, when duplicate sessions are selected, the following error is shown:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/validation-warning-duplicate-sessions.png?sfvrsn=38a76043_2" alt="Validation warning indicating duplicate sessions selected" /></p><p>With this, we have created cross-field validation correctly using Blazor.</p><h3 id="improving-validations-using-fieldcssclassprovider">Improving Validations Using FieldCssClassProvider</h3><p>At this point we have a project that correctly validates the form information, thanks to the native capabilities of <code>TelerikForm</code>. We can go one step further and modify the project to add visual indicators at the section level that communicate to the user which sections have errors. We can do this thanks to the method <code>EditContext.IsValid(fieldIdentifier)</code> introduced in .NET 10, which allows directly checking whether a field is valid.</p><p>To use it, the first thing we will do is create a class that inherits from <code>FieldCssClassProvider</code>. For the demonstration I will create a class called <code>RegistrationFieldClassProvider</code> at the root level of the project that looks as follows:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">RegistrationFieldClassProvider</span> <span class="token punctuation">:</span> FieldCssClassProvider
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">override</span> <span class="token keyword">string</span> <span class="token function">GetFieldCssClass</span><span class="token punctuation">(</span>EditContext editContext<span class="token punctuation">,</span> <span class="token keyword">in</span> FieldIdentifier fieldIdentifier<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>editContext<span class="token punctuation">.</span><span class="token function">IsModified</span><span class="token punctuation">(</span>fieldIdentifier<span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token keyword">return</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span>

        <span class="token keyword">var</span> isValid <span class="token operator">=</span> editContext<span class="token punctuation">.</span><span class="token function">IsValid</span><span class="token punctuation">(</span>fieldIdentifier<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> isValid <span class="token operator">?</span> <span class="token string">"is-valid"</span> <span class="token punctuation">:</span> <span class="token string">"is-invalid"</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>In the code above, it checks whether the field has been modified. Next <code>IsValid()</code> is used inside the method <code>GetFieldCssClass</code> to check if the field has associated validation messages. Finally, Bootstrap classes are returned that will provide feedback to the user about the validity of the sections.</p><p>To achieve this, we will make the card headers change color according to the state of their fields by modifying <code>Registration.razor</code> as follows:</p><ol><li>Add the event <code>OnValidSubmit</code> to <code>TelerikForm</code>:</li></ol><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikForm</span> <span class="token attr-name">EditContext</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>editContext<span class="token punctuation">"</span></span>
             <span class="token attr-name">OnValidSubmit</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>HandleValidSubmit<span class="token punctuation">"</span></span>
             <span class="token attr-name">OnInvalidSubmit</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>HandleInvalidSubmit<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
</code></pre><ol start="2"><li>Find the <code>h5</code> elements that reference <strong>Attendee Information</strong> and <strong>Billing Address</strong>, and modify their container <code>div</code> as follows:</li></ol><pre class=" language-xml"><code class="prism  language-xml"><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>card-header @GetAttendeeHeaderClass()<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>h5</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mb-0<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Attendee Information<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h5</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>card-header @GetBillingHeaderClass()<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>h5</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mb-0<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Billing Address<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h5</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><ol start="3"><li>Modify the code section by adding the following changes:</li></ol><pre class=" language-csharp"><code class="prism  language-csharp">@code <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 keyword">bool</span> hasValidated<span class="token punctuation">;</span>

    <span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token keyword">void</span> <span class="token function">OnInitialized</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        editContext <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">EditContext</span><span class="token punctuation">(</span>registration<span class="token punctuation">)</span><span class="token punctuation">;</span>
                
        editContext<span class="token punctuation">.</span><span class="token function">SetFieldCssClassProvider</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">RegistrationFieldClassProvider</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        editContext<span class="token punctuation">.</span>OnValidationStateChanged <span class="token operator">+</span><span class="token operator">=</span> <span class="token punctuation">(</span>_<span class="token punctuation">,</span> _<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token function">StateHasChanged</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        

        availableSessions <span class="token operator">=</span> SessionCatalog<span class="token punctuation">.</span><span class="token function">GetAvailableSessions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        preferenceLevels <span class="token operator">=</span> SessionCatalog<span class="token punctuation">.</span><span class="token function">GetPreferenceLevels</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 keyword">bool</span> <span class="token generic-method function">IsFieldValid<span class="token punctuation">&lt;</span>T<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span>Expression<span class="token operator">&lt;</span>Func<span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token operator">&gt;</span> accessor<span class="token punctuation">)</span>
       <span class="token operator">=</span><span class="token operator">&gt;</span> editContext<span class="token punctuation">.</span><span class="token function">IsValid</span><span class="token punctuation">(</span>FieldIdentifier<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span>accessor<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">private</span> <span class="token keyword">string</span> <span class="token function">GetAttendeeHeaderClass</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>hasValidated<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token string">"bg-primary text-white"</span><span class="token punctuation">;</span>

        <span class="token keyword">bool</span> allValid <span class="token operator">=</span> <span class="token function">IsFieldValid</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> registration<span class="token punctuation">.</span>Attendee<span class="token punctuation">.</span>FullName<span class="token punctuation">)</span>
            <span class="token operator">&amp;&amp;</span> <span class="token function">IsFieldValid</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> registration<span class="token punctuation">.</span>Attendee<span class="token punctuation">.</span>Email<span class="token punctuation">)</span>
            <span class="token operator">&amp;&amp;</span> <span class="token function">IsFieldValid</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> registration<span class="token punctuation">.</span>Attendee<span class="token punctuation">.</span>Phone<span class="token punctuation">)</span>
            <span class="token operator">&amp;&amp;</span> <span class="token function">IsFieldValid</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> registration<span class="token punctuation">.</span>Attendee<span class="token punctuation">.</span>Company<span class="token punctuation">)</span>
            <span class="token operator">&amp;&amp;</span> <span class="token function">IsFieldValid</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> registration<span class="token punctuation">.</span>Attendee<span class="token punctuation">.</span>JobTitle<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> allValid <span class="token operator">?</span> <span class="token string">"bg-success text-white"</span> <span class="token punctuation">:</span> <span class="token string">"bg-danger text-white"</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">string</span> <span class="token function">GetBillingHeaderClass</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>hasValidated<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token string">"bg-primary text-white"</span><span class="token punctuation">;</span>

        <span class="token keyword">bool</span> allValid <span class="token operator">=</span> <span class="token function">IsFieldValid</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> registration<span class="token punctuation">.</span>BillingAddress<span class="token punctuation">.</span>Street<span class="token punctuation">)</span>
            <span class="token operator">&amp;&amp;</span> <span class="token function">IsFieldValid</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> registration<span class="token punctuation">.</span>BillingAddress<span class="token punctuation">.</span>City<span class="token punctuation">)</span>
            <span class="token operator">&amp;&amp;</span> <span class="token function">IsFieldValid</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> registration<span class="token punctuation">.</span>BillingAddress<span class="token punctuation">.</span>State<span class="token punctuation">)</span>
            <span class="token operator">&amp;&amp;</span> <span class="token function">IsFieldValid</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> registration<span class="token punctuation">.</span>BillingAddress<span class="token punctuation">.</span>PostalCode<span class="token punctuation">)</span>
            <span class="token operator">&amp;&amp;</span> <span class="token function">IsFieldValid</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> registration<span class="token punctuation">.</span>BillingAddress<span class="token punctuation">.</span>Country<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> allValid <span class="token operator">?</span> <span class="token string">"bg-success text-white"</span> <span class="token punctuation">:</span> <span class="token string">"bg-danger text-white"</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">private</span> <span class="token keyword">void</span> <span class="token function">HandleValidSubmit</span><span class="token punctuation">(</span>EditContext context<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>        
        hasValidated <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">;</span>        
        isSubmitted <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
        
    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">HandleInvalidSubmit</span><span class="token punctuation">(</span>EditContext context<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        hasValidated <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>In the code above, I added the field <code>hasValidated</code> to check if the form has been submitted. I also modified <code>OnInitialized</code> by adding the handler for the event <code>OnValidationStateChanged</code>, which allows the UI to update reactively. I also added the helper <code>IsFieldValid&lt;T&gt;</code> and the methods <code>GetAttendeeHeaderClass</code> and <code>GetBillingHeaderClass</code>. This is the result:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-05/form-section-error-summary.png?sfvrsn=64b57388_2" alt="Form displaying an error summary for entire sections" /></p><p>With this, we have managed to give the user better feedback about the sections they need to complete before proceeding.</p><h2 id="conclusion">Conclusion</h2><p>Throughout this article, we have explored the new features available in .NET 10 that will undoubtedly help you manage forms with nested objects and lists. We&rsquo;ve also looked at how to perform cross-validations and, finally, the process of carrying out more complex validations by checking data in sections.</p><p>Now it&rsquo;s your time to implement these new features in your own projects and provide better feedback to your users.</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">120+ Enterprise-Grade Blazor UI Components</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Accelerate app development with <a target="_blank" href="https://www.telerik.com https://www.telerik.com/blazor-ui">Telerik UI for Blazor</a>&mdash;a complete set of 120+ high-performance, accessible controls, MCP Servers and more. Available with a free 30-day trial.</p></div></div></aside><img src="https://feeds.telerik.com/link/23050/17353268.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:1feea2d1-2fa0-48fa-a5fa-f1d611bdf2d5</id>
    <title type="text">Streaming Server Events with SSE and Blazor</title>
    <summary type="text">Understand the SSE standard, the .NET 10  changes to simplify SSE endpoints and how to add real-time events to your Blazor clients.</summary>
    <published>2026-05-12T13:18:03Z</published>
    <updated>2026-06-14T09:54:16Z</updated>
    <author>
      <name>Héctor Pérez </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23050/17339197/streaming-server-events-sse-blazor"/>
    <content type="text"><![CDATA[<p><span class="featured">Understand the SSE standard, the .NET 10 changes to simplify SSE endpoints and how to add real-time events to your Blazor clients.</span></p><p>In the world of web development, there are scenarios where you need to receive real-time information, such as notifications about an event, server metrics or live logs. One possible solution to achieve this is the use of Server-Sent Events (SSE). With the arrival of .NET 10, implementing this type of solution has become much easier, so let&rsquo;s see how to integrate this web standard into your projects.</p><h2 id="what-are-server-sent-events">What Are Server-Sent Events?</h2><p>The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events">Server-Sent Events (SSE)</a> are not a new technology. Their origins date back to around 2006, and they are a web standard that allows data to be sent to clients continuously using a persistent HTTP connection.</p><p>If you wonder the difference compared to other similar technologies, we can make a comparison:</p><ul><li><p><strong>SSE vs. Polling</strong>: In the case of polling, the direction goes from the client to the server, using the HTTP protocol. We can see it as a client asking the server if there are updates at certain intervals. It involves low implementation complexity.</p></li><li><p><strong>SSE vs. WebSockets</strong>: With WebSockets there is bidirectional communication. It involves high complexity and is ideal for scenarios like video games, chats, etc. It works over the WS protocol.</p></li><li><p><strong>SSE vs. SignalR</strong>: SignalR also establishes bidirectional communication, with medium implementation complexity. It allows the use of binary protocols, which makes it a very good option for scalable enterprise apps. It uses variable protocols.</p></li></ul><p>Analyzing the above, we can conclude that SSE is ideal when the data flow is unidirectional, you need it to work over the HTTP protocol and it must be easy to implement.</p><h2 id="how-does-the-sse-protocol-work">How Does the SSE Protocol Work?</h2><p>The workings behind the scenes of the SSE protocol, in broad terms, are as follows: a server SSE endpoint needs to send an HTTP response of the type <code>Content-Type: text/event-stream</code>. The response looks similar to the following:</p><pre class=" language-json"><code class="prism  language-json">event<span class="token punctuation">:</span> app<span class="token operator">-</span>event
data<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">"time"</span><span class="token punctuation">:</span><span class="token string">"10:30:45"</span><span class="token punctuation">,</span><span class="token string">"level"</span><span class="token punctuation">:</span><span class="token string">"Info"</span><span class="token punctuation">,</span><span class="token string">"source"</span><span class="token punctuation">:</span><span class="token string">"OrderService"</span><span class="token punctuation">,</span><span class="token string">"message"</span><span class="token punctuation">:</span><span class="token string">"Order #1234 placed successfully"</span><span class="token punctuation">}</span>
</code></pre><p>In the code above, there are some fields we should pay attention to:</p><ul><li><code>event</code>: Specifies the name of the event</li><li><code>data</code>: Is the content of the message</li><li><code>id</code>: Identifier used to perform a reconnection if needed</li></ul><h2 id="whats-new-in-.net-10-for-sse">What&rsquo;s New in .NET 10 for SSE</h2><p>The most important update in .NET 10 for working with SSE is that the ability to return a <code>ServerSentEvents</code> using the API <code>TypedResults.ServerSentEvents</code> has been implemented. This means that the method <code>TypedResults.ServerSentEvents&lt;T&gt;()</code> allows converting any <code>IAsyncEnumerable&lt;T&gt;</code> into a formatted SSE stream without needing to do anything else. Tasks like JSON serialization, HTTP headers, connection closing, etc. are handled automatically.</p><p>To better understand how it works, let&rsquo;s create a project using the SSE standard with ASP.NET 10.</p><h2 id="building-an-sse-project-using-asp.net-10">Building an SSE Project Using ASP.NET 10</h2><p>To practice the theoretical concepts covered so far, we&rsquo;ll create a page that shows a simulation of receiving events from backend services in real time. Using a Progress Telerik UI for <a target="_blank" href="https://www.telerik.com/blazor-ui/grid">Blazor Grid</a>, we&rsquo;ll perform tasks like filtering, grouping and analysis quickly.</p><h3 id="creating-and-configuring-the-project">Creating and Configuring the Project</h3><p>The first thing we&rsquo;ll do is create a project using the <strong>Blazor Web App</strong> template, selecting an <strong>Interactive render mode</strong> of <strong>Server</strong> and <strong>Interactivity location</strong> of <strong>Global</strong>. Next, we&rsquo;ll follow the official installation guide for <a target="_blank" href="https://www.telerik.com/blazor-ui">Telerik UI for Blazor</a> to configure the project and be able to use the Telerik components.</p><h3 id="creating-an-eventbroadcaster">Creating an EventBroadcaster</h3><p>For our project, we&rsquo;ll create an event broadcaster, which in simple terms will be a bus that SSE clients can connect to to consume events, while backend services will use it to publish events. First, we&rsquo;ll create a record that represents a system event:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">namespace</span> SSEDemo<span class="token punctuation">.</span>Services
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> record <span class="token function">AppEvent</span><span class="token punctuation">(</span><span class="token keyword">int</span> Id<span class="token punctuation">,</span> <span class="token keyword">string</span> Time<span class="token punctuation">,</span> <span class="token keyword">string</span> Level<span class="token punctuation">,</span> <span class="token keyword">string</span> Source<span class="token punctuation">,</span> <span class="token keyword">string</span> Message<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Next, we will create the class <code>EventBroadcaster</code> which will have the following definition:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">EventBroadcaster</span>
<span class="token punctuation">{</span>
    <span class="token comment">//1.</span>
    <span class="token keyword">private</span> <span class="token keyword">readonly</span> Channel<span class="token operator">&lt;</span>AppEvent<span class="token operator">&gt;</span> _channel <span class="token operator">=</span> Channel<span class="token punctuation">.</span><span class="token generic-method function">CreateBounded<span class="token punctuation">&lt;</span>AppEvent<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span>
    <span class="token keyword">new</span> <span class="token class-name">BoundedChannelOptions</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> FullMode <span class="token operator">=</span> BoundedChannelFullMode<span class="token punctuation">.</span>DropOldest <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">private</span> <span class="token keyword">int</span> _nextId<span class="token punctuation">;</span>

    <span class="token comment">// 2.</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">Publish</span><span class="token punctuation">(</span><span class="token keyword">string</span> level<span class="token punctuation">,</span> <span class="token keyword">string</span> source<span class="token punctuation">,</span> <span class="token keyword">string</span> message<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">var</span> id <span class="token operator">=</span> Interlocked<span class="token punctuation">.</span><span class="token function">Increment</span><span class="token punctuation">(</span><span class="token keyword">ref</span> _nextId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">var</span> evt <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AppEvent</span><span class="token punctuation">(</span>id<span class="token punctuation">,</span> DateTime<span class="token punctuation">.</span>Now<span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token string">"HH:mm:ss"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> level<span class="token punctuation">,</span> source<span class="token punctuation">,</span> message<span class="token punctuation">)</span><span class="token punctuation">;</span>
        _channel<span class="token punctuation">.</span>Writer<span class="token punctuation">.</span><span class="token function">TryWrite</span><span class="token punctuation">(</span>evt<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 3.</span>
    <span class="token keyword">public</span> <span class="token keyword">async</span> IAsyncEnumerable<span class="token operator">&lt;</span>AppEvent<span class="token operator">&gt;</span> <span class="token function">Subscribe</span><span class="token punctuation">(</span>
        <span class="token punctuation">[</span>System<span class="token punctuation">.</span>Runtime<span class="token punctuation">.</span>CompilerServices<span class="token punctuation">.</span>EnumeratorCancellation<span class="token punctuation">]</span> CancellationToken ct<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token operator">!</span>ct<span class="token punctuation">.</span>IsCancellationRequested<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">bool</span> hasData<span class="token punctuation">;</span>
            <span class="token keyword">try</span>
            <span class="token punctuation">{</span>
                hasData <span class="token operator">=</span> <span class="token keyword">await</span> _channel<span class="token punctuation">.</span>Reader<span class="token punctuation">.</span><span class="token function">WaitToReadAsync</span><span class="token punctuation">(</span>ct<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><span class="token class-name">OperationCanceledException</span><span class="token punctuation">)</span>
            <span class="token punctuation">{</span>
                <span class="token keyword">yield</span> <span class="token keyword">break</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>hasData<span class="token punctuation">)</span> <span class="token keyword">yield</span> <span class="token keyword">break</span><span class="token punctuation">;</span>

            <span class="token keyword">while</span> <span class="token punctuation">(</span>_channel<span class="token punctuation">.</span>Reader<span class="token punctuation">.</span><span class="token function">TryRead</span><span class="token punctuation">(</span><span class="token keyword">out</span> <span class="token keyword">var</span> evt<span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token punctuation">{</span>
                <span class="token keyword">yield</span> <span class="token keyword">return</span> evt<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 code above, we have the following sections:</p><ol><li><p>Sets up the channel where events will be passed, with a queue limit of 100 messages. <code>FullMode = BoundedChannelFullMode.DropOldest</code> allows that if the queue fills up and a new message arrives, the oldest one is removed to make room for the new message.</p></li><li><p>The method <code>Publish</code> is the one that will be used to emit events. <code>Interlocked.Increment</code> allows generating sequential IDs in a safe manner, while <code>AppEvent</code> packages the received data together with the obtained id. Finally the method <code>TryWrite()</code> attempts to write the event to the channel asynchronously.</p></li><li><p>On the other hand, the method <code>Subscribe</code> returns a continuous stream of asynchronous data through the use of <code>IAsyncEnumerable&lt;AppEvent&gt;</code>. Inside its implementation an infinite loop is created that waits for data to be available in the channel. Once an event enters the channel, it is emitted to the consumer. This will happen until the <code>CancellationToken</code> called <code>ct</code> is canceled.</p></li></ol><h3 id="generating-test-events">Generating Test Events</h3><p>To test the bus defined above, we&rsquo;ll create a service that simulates the activity of multiple services:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DemoEventGenerator</span><span class="token punctuation">(</span>EventBroadcaster broadcaster<span class="token punctuation">)</span> <span class="token punctuation">:</span> BackgroundService
<span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">readonly</span> <span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span> Levels <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"Info"</span><span class="token punctuation">,</span> <span class="token string">"Warning"</span><span class="token punctuation">,</span> <span class="token string">"Error"</span><span class="token punctuation">,</span> <span class="token string">"Success"</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">readonly</span> <span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span> Sources <span class="token operator">=</span>
        <span class="token punctuation">[</span><span class="token string">"OrderService"</span><span class="token punctuation">,</span> <span class="token string">"PaymentService"</span><span class="token punctuation">,</span> <span class="token string">"InventoryService"</span><span class="token punctuation">,</span> <span class="token string">"AuthService"</span><span class="token punctuation">,</span> <span class="token string">"ShippingService"</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">readonly</span> <span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token punctuation">]</span> Messages <span class="token operator">=</span>
    <span class="token punctuation">[</span>
        <span class="token punctuation">[</span><span class="token string">"Order #{0} placed successfully"</span><span class="token punctuation">,</span> <span class="token string">"New customer registered"</span><span class="token punctuation">,</span> <span class="token string">"Product viewed: SKU-{0}"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token punctuation">[</span><span class="token string">"High latency detected: {0}ms"</span><span class="token punctuation">,</span> <span class="token string">"Retry attempt #{0}"</span><span class="token punctuation">,</span> <span class="token string">"Queue depth above threshold"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token punctuation">[</span><span class="token string">"Payment failed for order #{0}"</span><span class="token punctuation">,</span> <span class="token string">"Database timeout after {0}ms"</span><span class="token punctuation">,</span> <span class="token string">"Service unreachable"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token punctuation">[</span><span class="token string">"Deployment completed v2.{0}"</span><span class="token punctuation">,</span> <span class="token string">"Health check passed"</span><span class="token punctuation">,</span> <span class="token string">"Cache refreshed ({0} items)"</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">override</span> <span class="token keyword">async</span> Task <span class="token function">ExecuteAsync</span><span class="token punctuation">(</span>CancellationToken stoppingToken<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">var</span> rng <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token operator">!</span>stoppingToken<span class="token punctuation">.</span>IsCancellationRequested<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>            
            <span class="token keyword">await</span> Task<span class="token punctuation">.</span><span class="token function">Delay</span><span class="token punctuation">(</span>rng<span class="token punctuation">.</span><span class="token function">Next</span><span class="token punctuation">(</span><span class="token number">1500</span><span class="token punctuation">,</span> <span class="token number">4000</span><span class="token punctuation">)</span><span class="token punctuation">,</span> stoppingToken<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">var</span> levelIdx <span class="token operator">=</span> rng<span class="token punctuation">.</span><span class="token function">Next</span><span class="token punctuation">(</span>Levels<span class="token punctuation">.</span>Length<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">var</span> level <span class="token operator">=</span> Levels<span class="token punctuation">[</span>levelIdx<span class="token punctuation">]</span><span class="token punctuation">;</span>
            <span class="token keyword">var</span> source <span class="token operator">=</span> Sources<span class="token punctuation">[</span>rng<span class="token punctuation">.</span><span class="token function">Next</span><span class="token punctuation">(</span>Sources<span class="token punctuation">.</span>Length<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
            <span class="token keyword">var</span> templates <span class="token operator">=</span> Messages<span class="token punctuation">[</span>levelIdx<span class="token punctuation">]</span><span class="token punctuation">;</span>
            <span class="token keyword">var</span> message <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">Format</span><span class="token punctuation">(</span>templates<span class="token punctuation">[</span>rng<span class="token punctuation">.</span><span class="token function">Next</span><span class="token punctuation">(</span>templates<span class="token punctuation">.</span>Length<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> rng<span class="token punctuation">.</span><span class="token function">Next</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">,</span> <span class="token number">9999</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            broadcaster<span class="token punctuation">.</span><span class="token function">Publish</span><span class="token punctuation">(</span>level<span class="token punctuation">,</span> source<span class="token punctuation">,</span> message<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 previous class is a random event generator, taking a random value from the arrays <code>Levels</code>, <code>Sources</code> and <code>Messages</code>. In addition, through the parameter <code>broadcaster</code>, the new event is published to the bus.</p><h3 id="creating-the-sse-endpoint">Creating the SSE Endpoint</h3><p>Now it&rsquo;s time to create the SSE endpoint, which will consume the shared <code>EventBroadcaster</code>, with the purpose of creating the Event Feed so clients can connect to receive events:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">SseEndpoints</span>
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">MapSseEndpoints</span><span class="token punctuation">(</span><span class="token keyword">this</span> WebApplication app<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>        
        app<span class="token punctuation">.</span><span class="token function">MapGet</span><span class="token punctuation">(</span><span class="token string">"/sse/events"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>EventBroadcaster broadcaster<span class="token punctuation">,</span> CancellationToken ct<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span>
            TypedResults<span class="token punctuation">.</span><span class="token function">ServerSentEvents</span><span class="token punctuation">(</span>broadcaster<span class="token punctuation">.</span><span class="token function">Subscribe</span><span class="token punctuation">(</span>ct<span class="token punctuation">)</span><span class="token punctuation">,</span> eventType<span class="token punctuation">:</span> <span class="token string">"app-event"</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 code above you can notice how <code>EventBroadcaster</code> is injected as a parameter of <code>MapGet</code>. Likewise, <code>TypedResults.ServerSentEvent</code> is executed, which serializes the information and sends the correct SSE format to clients.</p><h3 id="registering-services-in-program.cs">Registering Services in Program.cs</h3><p>For everything to work as expected, we must register in <code>Program.cs</code> the different instances that will interact in the Blazor application. This means creating a singleton instance of <code>EventBroadcaster</code>, so that all systems have access to the same bus. Similarly, we will register <code>DemoEventGenerator</code> as a background service, through the method <code>AddHostedService</code>. This will allow simulated events to be generated in the background continuously:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">var</span> builder <span class="token operator">=</span> WebApplication<span class="token punctuation">.</span><span class="token function">CreateBuilder</span><span class="token punctuation">(</span>args<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>
builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method function">AddSingleton<span class="token punctuation">&lt;</span>EventBroadcaster<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method function">AddHostedService<span class="token punctuation">&lt;</span>DemoEventGenerator<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">var</span> app <span class="token operator">=</span> builder<span class="token punctuation">.</span><span class="token function">Build</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>

app<span class="token punctuation">.</span><span class="token function">MapSseEndpoints</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

app<span class="token punctuation">.</span><span class="token function">Run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In the previous code, in addition to registering the services, <code>MapSseEndpoints</code> is invoked to enable SSE communication in the project.</p><h3 id="creating-the-blazor-application">Creating the Blazor Application</h3><p>Once we have the application infrastructure ready, it&rsquo;s time to move on to the UI part. At this point, let&rsquo;s start by creating a JavaScript client, because the standard requires using the browser&rsquo;s <code>EventSource</code> API. Since the project is configured as <code>InteractiveServer</code>, we cannot add inline <code>script</code> tags. To work around this, I will add a new file inside the <code>wwwroot/js</code> folder called <code>sse-demos.js</code>:</p><pre class=" language-javascript"><code class="prism  language-javascript"><span class="token comment">//1.</span>
<span class="token keyword">let</span> eventFeedSource <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

<span class="token number">2</span><span class="token punctuation">.</span>
<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">start</span><span class="token punctuation">(</span>dotNetRef<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 3.</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>eventFeedSource<span class="token punctuation">)</span> eventFeedSource<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">//4.</span>
    <span class="token keyword">const</span> src <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">EventSource</span><span class="token punctuation">(</span><span class="token string">'/sse/events'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// 5.</span>
    src<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'app-event'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        dotNetRef<span class="token punctuation">.</span><span class="token function">invokeMethodAsync</span><span class="token punctuation">(</span><span class="token string">'OnEventReceived'</span><span class="token punctuation">,</span> JSON<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>e<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><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// 6.</span>
    src<span class="token punctuation">.</span><span class="token function-variable function">onopen</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> dotNetRef<span class="token punctuation">.</span><span class="token function">invokeMethodAsync</span><span class="token punctuation">(</span><span class="token string">'OnConnectionChanged'</span><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>
    src<span class="token punctuation">.</span><span class="token function-variable function">onerror</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> dotNetRef<span class="token punctuation">.</span><span class="token function">invokeMethodAsync</span><span class="token punctuation">(</span><span class="token string">'OnConnectionChanged'</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>

    eventFeedSource <span class="token operator">=</span> src<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">//7.</span>
<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">stop</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>eventFeedSource<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        eventFeedSource<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        eventFeedSource <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>The previous code does the following:</p><ol><li>A variable <code>eventFeedSource</code> is created to keep information about whether there is an active connection with the server.</li><li>A function named <code>start</code> should be called from C# code when you want to start receiving information&hellip;</li><li>It checks whether there is an open connection, in which case it is closed.</li><li>It tells the browser to connect to <code>/sse/events</code> and to listen for all events that the server sends.</li><li>It filters events named <code>app-event</code>.</li><li>We subscribe to the events <code>onopen</code> and <code>onerror</code>. Each will notify the method <code>OnConnectionChanged</code> about a change in the connection, which will allow showing a different state in the Blazor UI.</li><li>The function <code>stop</code> should be invoked to clean up memory when we want to close the connection.</li></ol><p>With the JS functions ready, the next step is to create the Blazor component. In this new component we will use a <a target="_blank" href="https://www.telerik.com/blazor-ui/grid">Blazor Data Grid</a> type component, because it is a highly configurable component that has built-in options to filter, group, etc., ideal for quickly obtaining information about events in the different systems.</p><p>To do the above, we will create a component called <code>EventFeed.razor</code>, which looks as follows:</p><pre class=" language-xml"><code class="prism  language-xml">@page "/events"
@rendermode InteractiveServer
@inject IJSRuntime JS
@implements IAsyncDisposable

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>PageTitle</span><span class="token punctuation">&gt;</span></span>Live Event Feed<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>PageTitle</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mb-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Live Event Feed<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>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>card shadow-sm<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>card-header d-flex align-items-center justify-content-between py-2<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>d-flex align-items-center gap-3<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            @if (isStreaming)
            {
                &lt;span class="badge rounded-pill @(isConnected ? "bg-success" : "bg-secondary") fs-6"&gt;
                    <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>me-1<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>span</span><span class="token punctuation">&gt;</span></span>@(isConnected ? "Connected" : "Disconnected")
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
            }
            else
            {
                <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>badge rounded-pill bg-warning text-dark fs-6<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>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>me-1<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>span</span><span class="token punctuation">&gt;</span></span>Paused
                <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>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-muted<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                Events received: <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>strong</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-dark<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@totalEventsReceived<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</span><span class="token punctuation">&gt;</span></span>
            <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>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>d-flex gap-2<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>TelerikButton</span> <span class="token attr-name">OnClick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ToggleStreaming<span class="token punctuation">"</span></span>
                           <span class="token attr-name">ThemeColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@(isStreaming ? ThemeConstants.Button.ThemeColor.Primary : ThemeConstants.Button.ThemeColor.Success)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                @(isStreaming ? "⏸ Pause" : "▶ Resume")
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikButton</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikButton</span> <span class="token attr-name">OnClick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ClearGrid<span class="token punctuation">"</span></span> <span class="token attr-name">ThemeColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.Button.ThemeColor.Light<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span> Clear<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikButton</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>
    <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>card-body p-0<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>TelerikGrid</span> <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@events<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>560px<span class="token punctuation">"</span></span>
                     <span class="token attr-name">Sortable</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">Resizable</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">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">Groupable</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">ShowColumnMenu</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 punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridColumns</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridColumn</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@nameof(AppEvent.Time)<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>Time<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>110px<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>GridColumn</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@nameof(AppEvent.Level)<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>Level<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>120px<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>Template</span><span class="token punctuation">&gt;</span></span>
                        @{
                            var item = (AppEvent)context;
                        }
                        <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>badge rounded-pill @GetBadgeClass(item.Level) px-3 py-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@item.Level<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>Template</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>GridColumn</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridColumn</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@nameof(AppEvent.Source)<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>Source<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>140px<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>GridColumn</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@nameof(AppEvent.Message)<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>Message<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>GridColumns</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikGrid</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 {
    private List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>AppEvent</span><span class="token punctuation">&gt;</span></span> events = new();
    private bool isConnected;
    private bool isStreaming = true;
    private int totalEventsReceived;
    private DotNetObjectReference<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>EventFeed</span><span class="token punctuation">&gt;</span></span>? dotNetRef;
    private IJSObjectReference? jsModule;
    private bool _jsInitialized;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            dotNetRef = DotNetObjectReference.Create(this);
                       
            jsModule = await JS.InvokeAsync<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>IJSObjectReference</span><span class="token punctuation">&gt;</span></span>("import", "./js/sse-demos.js");
                        
            await jsModule.InvokeVoidAsync("start", dotNetRef);
            
            _jsInitialized = true;
        }
    }

    [JSInvokable]
    public void OnEventReceived(AppEvent appEvent)
    {
        totalEventsReceived++;
        var updated = new List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>AppEvent</span><span class="token punctuation">&gt;</span></span>(events);
        updated.Insert(0, appEvent);
        if (updated.Count &gt; 50)
            updated.RemoveRange(50, updated.Count - 50);
        events = updated;
        InvokeAsync(StateHasChanged);
    }

    [JSInvokable]
    public void OnConnectionChanged(bool connected)
    {
        isConnected = connected;
        InvokeAsync(StateHasChanged);
    }

    private async Task ToggleStreaming()
    {
        isStreaming = !isStreaming;
        
        if (jsModule is not null)
        {
            if (isStreaming)
                await jsModule.InvokeVoidAsync("start", dotNetRef);
            else
                await jsModule.InvokeVoidAsync("stop");
        }
    }

    private void ClearGrid()
    {
        events = new List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>AppEvent</span><span class="token punctuation">&gt;</span></span>();
        StateHasChanged();
    }

    private string GetBadgeClass(string level) =&gt; level switch
    {
        "Info" =&gt; "bg-info text-dark",
        "Warning" =&gt; "bg-warning text-dark",
        "Error" =&gt; "bg-danger",
        "Success" =&gt; "bg-success",
        _ =&gt; "bg-secondary"
    };

    public async ValueTask DisposeAsync()
    {
        if (_jsInitialized &amp;&amp; jsModule is not null)
        {
            try
            {                
                await jsModule.InvokeVoidAsync("stop");
                                
                await jsModule.DisposeAsync();
            }
            catch
            {                
            }
        }
        dotNetRef?.Dispose();
    }

    public class AppEvent
    {
        public int Id { get; set; }
        public string Time { get; set; } = string.Empty;
        public string Level { get; set; } = string.Empty;
        public string Source { get; set; } = string.Empty;
        public string Message { get; set; } = string.Empty;
    }
}
</code></pre><p>In the previous code, there are some points to highlight:</p><ul><li><code>jsModule</code> dynamically loads the JS module.</li><li>The variable <code>dotNetRef</code> wraps the instance of the Blazor component that we will use inside the JS code.</li><li>The method <code>InvokeVoidAsync</code> is used both to start and to stop the event streaming.</li><li>The method <code>OnEventReceived</code> is invoked from the JS code each time an event is received. This allows updating the list <code>events</code> to show the new information in <code>TelerikGrid</code>.</li><li>The <code>OnConnectionChanged</code> method receives a connection status from the JS code to update the UI according to any change in the connection.</li></ul><p>With the new component ready, we can test the application, which looks like the following:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/telerik-datagrid-sse-event-feed.gif?sfvrsn=58cc913a_2" alt="Telerik DataGrid receiving live SSE event feed" /></p><p>With this, we verify that everything works correctly. Also, thanks to the Blazor DataGrid capabilities, we can perform operations such as monitoring only those high-severity events:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/timeline-grouped-events-view.png?sfvrsn=5ae1f10_2" alt="Timeline view of events grouped by day" /></p><p>With this we have a nice event viewer that monitors the status of multiple fictitious systems.</p><h2 id="conclusion">Conclusion</h2><p>Throughout this article you have learned about the SSE standard. You have also seen how changes introduced in .NET 10 help simplify the creation of SSE endpoints, enabling the creation of applications that send real-time events to clients. Now it&rsquo;s your turn to explore when you might use this web standard in your own projects. See you in the next article!</p><hr /><p>Try all this yourself with a free 30-day trial of Telerik UI for Blazor.</p><p><a href="https://www.telerik.com/try/ui-for-blazor" target="_blank" class="Btn">Try Now</a></p><img src="https://feeds.telerik.com/link/23050/17339197.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:2c9543f6-911a-443f-8612-e1d7e336574b</id>
    <title type="text">Routing Management and Creating NotFound Pages in Blazor</title>
    <summary type="text">Route handling got better in .NET 10. Let’s see how to create context for managing information on an error page and show users specific error pages.</summary>
    <published>2026-05-05T15:57:00Z</published>
    <updated>2026-06-14T09:54:16Z</updated>
    <author>
      <name>Héctor Pérez </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23050/17334920/routing-management-creating-notfound-pages-blazor"/>
    <content type="text"><![CDATA[<p><span class="featured">Route handling got better in .NET 10. Let&rsquo;s see how to create context for managing information on an error page and show users specific error pages.</span></p><p>If you have worked with Blazor in versions prior to .NET 10, you have certainly encountered some difficulties in implementing not found pages and in handling NavLink to show users the page they are currently on.</p><p>This is why, during the last update to .NET 10, the team behind Blazor has significantly improved the handling of routes and the management of not found pages. In this article, we will analyze the most important aspects. Let&rsquo;s get started!</p><h2 id="understanding-the-handling-of-not-found-routes-in-blazor">Understanding the Handling of Not Found Routes in Blazor</h2><p>When we talk about routing, we refer to the mechanism that allows the user to navigate to a specific component based on the requested URL. However, there may be times when there are non-existent URLs that the user attempts to navigate to, such as when an item has been deleted or when, for some reason, a page has been removed from the site.</p><p>Properly handling these scenarios is essential for a good user experience, good SEO and, in general, having a reliable web application.</p><h2 id="the-problem-with-not-found-pages-before-.net-10">The Problem with Not Found Pages Before .NET 10</h2><p>You should know that before .NET 10, as part of the <code>Router</code> component, there was a render fragment called <code>NotFound</code>, which at first glance could lead us to think that it allowed defining graphical code to show content when a route was not found:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Router</span> <span class="token attr-name">AppAssembly</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>typeof(Program).Assembly<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>Found</span> <span class="token attr-name">Context</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>routeData<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>Found</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>NotFound</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>LayoutView</span> <span class="token attr-name">Layout</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>typeof(Layout.MainLayout)<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>h1</span><span class="token punctuation">&gt;</span></span>Page not found<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>Sorry, but there is nothing here!<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>LayoutView</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>NotFound</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Router</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>In practice, something different occurred, as when attempting to navigate to a non-existent page, an error page was displayed instead of the defined graphical code:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/net9-render-fragment-notfound-logic.gif?sfvrsn=d61310e6_2" alt="Execution flow of &#39;NotFound&#39; RenderFragment in .NET 9 routing" /></p><p>Another technique that was used before .NET 10 was to handle the not found page code within the components. For example, there could be an ecommerce-type application with a products page and a product details page. On the product details page, if the user tried to access a non-existent page, it was handled similarly to the following way:</p><pre class=" language-xml"><code class="prism  language-xml">@if (product == null)
{    
    <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>alert alert-warning text-center<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>alert<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>h4</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>alert-heading<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Product Not Found<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h4</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>The product with ID <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>strong</span><span class="token punctuation">&gt;</span></span>@Id<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</span><span class="token punctuation">&gt;</span></span> does not exist in our catalog.<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>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">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>btn btn-outline-primary<span class="token punctuation">"</span></span> <span class="token attr-name">@onclick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>GoBack<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token entity" title="←">&amp;larr;</span> Back to Products
        <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>
}
else
{
    ...
}
</code></pre><p>The execution of the previous code resulted in the following appearance:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/handling-notfound-errors-net9.png?sfvrsn=8f3d31f2_2" alt="Handling Not Found errors in .NET 9" /></p><p>The previous code, although it achieved the goal of showing the user that the product did not exist, had several problems:</p><ul><li>It returned an HTTP 200 code, not a 404.</li><li>Each component had to implement its own logic.</li><li>If there was navigation to a non-existent URL (not handled by a component), a site error page was shown.</li></ul><p>Next, let&rsquo;s see how .NET 10 improves the handling of not found pages.</p><h2 id="features-in-.net-10-for-route-management">Features in .NET 10 for Route Management</h2><p>In .NET 10, things have changed regarding route management. Let&rsquo;s analyze what these new features are.</p><h3 id="the-router.notfoundpage-parameter">The Router.NotFoundPage Parameter</h3><p>One of the most prominent updates is the addition of the <code>NotFoundPage</code> parameter to the <code>Router</code> component, which allows specifying a Razor page component that will be displayed when a route is not found. By default, in Blazor projects starting from .NET 10, in the <code>Pages</code> folder we find a component called <code>NotFound.razor</code>, whose structure is as follows:</p><p><strong>NotFound.razor</strong></p><pre class=" language-xml"><code class="prism  language-xml">@page "/not-found"
@layout MainLayout

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h3</span><span class="token punctuation">&gt;</span></span>Not Found<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h3</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>Sorry, the content you are looking for does not exist.<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><strong>Routes.razor</strong></p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Router</span> <span class="token attr-name">AppAssembly</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>typeof(Program).Assembly<span class="token punctuation">"</span></span> <span class="token attr-name">NotFoundPage</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>typeof(Pages.NotFound)<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>Router</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>The preview of this code gives the following result:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/default-notfoundpage-component-net10.png?sfvrsn=8d90d029_2" alt="Default NotFoundPage component behavior in .NET 10" /></p><p>In the code above, we can see that the 404 error page must include the <code>@page</code> directive for it to function correctly.</p><h3 id="customizing-the-notfound-component">Customizing the NotFound Component</h3><p>With the <code>NotFound.razor</code> component showing us how to implement a 404 page in our Blazor apps, the next step is to customize it. There are several ways to do this. For example, by adding support for contextual messages through a service class called <code>NotFoundContext</code>:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">NotFoundContext</span>
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span><span class="token operator">?</span> Heading <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span><span class="token operator">?</span> Message <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">UpdateContext</span><span class="token punctuation">(</span><span class="token keyword">string</span> heading<span class="token punctuation">,</span> <span class="token keyword">string</span> message<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        Heading <span class="token operator">=</span> heading<span class="token punctuation">;</span>
        Message <span class="token operator">=</span> message<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>This class will allow you to show a custom heading and message based on the operation the user has requested. For it to work correctly, you need to register the service in <code>Program.cs</code>:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">var</span> builder <span class="token operator">=</span> WebApplication<span class="token punctuation">.</span><span class="token function">CreateBuilder</span><span class="token punctuation">(</span>args<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>
builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method function">AddScoped<span class="token punctuation">&lt;</span>NotFoundContext<span class="token punctuation">&gt;</span></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">var</span> app <span class="token operator">=</span> builder<span class="token punctuation">.</span><span class="token function">Build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Now, let&rsquo;s give a bit more design to the <code>NotFound.razor</code> template:</p><pre class=" language-xml"><code class="prism  language-xml">@page "/not-found"
@layout MainLayout
@using NotFoundManagementNET102.Services
@inject NotFoundContext NotFoundContext

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>PageTitle</span><span class="token punctuation">&gt;</span></span>Not Found<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>PageTitle</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>container mt-5<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>row justify-content-center<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>col-md-8 col-lg-6<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>card shadow-sm border-0 text-center<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>card-body p-5<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>mb-4<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>svg</span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<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>80<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>80<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#6c757d<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>bi bi-exclamation-triangle<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0 0 16 16<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>path</span> <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>M7.938 2.016A.13.13 0 0 1 8.002 2a.13.13 0 0 1 .063.016...<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>svg</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>h3</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>card-title text-dark mb-3<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                        @(NotFoundContext.Heading ?? "Page Not Found")
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h3</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 attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>card-text text-muted mb-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                        @(NotFoundContext.Message ?? "Sorry, the content you are looking for does not exist.")
                    <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>d-flex justify-content-center gap-2<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>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/products<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>btn btn-primary<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                            <span class="token entity" title="←">&amp;larr;</span> Back to Products
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</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">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>btn btn-outline-secondary<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                            Go Home
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</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>
            <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>
    <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>In the code above, you can notice that it checks whether the user sets a value for <code>Heading</code> and <code>Message</code>, in order to display either a generic message or a personalized one. Let&rsquo;s see next how to display custom pages based on the user&rsquo;s context.</p><h3 id="handling-not-found-pages-with-navigationmanager.notfound-and-onnotfound">Handling Not Found Pages with NavigationManager.NotFound() and OnNotFound</h3><p>In .NET 9, <code>NavigationManager.NotFound()</code> and <code>OnNotFound</code> were introduced as part of the framework improvements for handling not found pages. We can combine both with the <code>NotFoundContext</code> service to display a 404 response and custom messages, through the following code:</p><pre class=" language-csharp"><code class="prism  language-csharp">@page <span class="token string">"/product/{Id:int}"</span>
@<span class="token keyword">using</span> NotFoundManagementNET102<span class="token punctuation">.</span>Models
@<span class="token keyword">using</span> NotFoundManagementNET102<span class="token punctuation">.</span>Services
@implements <span class="token class-name">IDisposable</span>
@inject ProductService ProductService
@inject NavigationManager Navigation
@inject NotFoundContext NotFoundContext

<span class="token operator">&lt;</span>PageTitle<span class="token operator">&gt;</span>@<span class="token punctuation">(</span>product<span class="token operator">?</span><span class="token punctuation">.</span>Name <span class="token operator">?</span><span class="token operator">?</span> <span class="token string">"Product Detail"</span><span class="token punctuation">)</span><span class="token operator">&lt;</span><span class="token operator">/</span>PageTitle<span class="token operator">&gt;</span>

@<span class="token keyword">if</span> <span class="token punctuation">(</span>product <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"container mt-4"</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>nav aria<span class="token operator">-</span>label<span class="token operator">=</span><span class="token string">"breadcrumb"</span><span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>ol <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"breadcrumb"</span><span class="token operator">&gt;</span>
                <span class="token operator">&lt;</span>li <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"breadcrumb-item"</span><span class="token operator">&gt;</span><span class="token operator">&lt;</span>a href<span class="token operator">=</span><span class="token string">"/products"</span><span class="token operator">&gt;</span>Products<span class="token operator">&lt;</span><span class="token operator">/</span>a<span class="token operator">&gt;</span><span class="token operator">&lt;</span><span class="token operator">/</span>li<span class="token operator">&gt;</span>
                <span class="token operator">&lt;</span>li <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"breadcrumb-item active"</span> aria<span class="token operator">-</span>current<span class="token operator">=</span><span class="token string">"page"</span><span class="token operator">&gt;</span>@product<span class="token punctuation">.</span>Name<span class="token operator">&lt;</span><span class="token operator">/</span>li<span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span><span class="token operator">/</span>ol<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span><span class="token operator">/</span>nav<span class="token operator">&gt;</span>

        <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"card shadow-sm"</span><span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"card-body"</span><span class="token operator">&gt;</span>
                <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"row"</span><span class="token operator">&gt;</span>
                    <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"col-md-8"</span><span class="token operator">&gt;</span>
                        <span class="token operator">&lt;</span>h2 <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"card-title"</span><span class="token operator">&gt;</span>@product<span class="token punctuation">.</span>Name<span class="token operator">&lt;</span><span class="token operator">/</span>h2<span class="token operator">&gt;</span>
                        <span class="token operator">&lt;</span>span <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"badge bg-secondary mb-3"</span><span class="token operator">&gt;</span>@product<span class="token punctuation">.</span>Category<span class="token operator">&lt;</span><span class="token operator">/</span>span<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">"card-text text-muted"</span><span class="token operator">&gt;</span>@product<span class="token punctuation">.</span>Description<span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">&gt;</span>

                        <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"row mt-4"</span><span class="token operator">&gt;</span>
                            <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"col-6"</span><span class="token operator">&gt;</span>
                                <span class="token operator">&lt;</span>h5<span class="token operator">&gt;</span>Price<span class="token operator">&lt;</span><span class="token operator">/</span>h5<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">"fs-4 text-primary fw-bold"</span><span class="token operator">&gt;</span>$@product<span class="token punctuation">.</span>Price<span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token string">"N2"</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>div<span class="token operator">&gt;</span>
                            <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"col-6"</span><span class="token operator">&gt;</span>
                                <span class="token operator">&lt;</span>h5<span class="token operator">&gt;</span>Stock<span class="token operator">&lt;</span><span class="token operator">/</span>h5<span class="token operator">&gt;</span>
                                <span class="token operator">&lt;</span>span <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"badge @(product.Stock &gt; 30 ? "</span>bg<span class="token operator">-</span>success<span class="token string">" : product.Stock &gt; 10 ? "</span>bg<span class="token operator">-</span>warning<span class="token string">" : "</span>bg<span class="token operator">-</span>danger<span class="token string">") fs-6"</span><span class="token operator">&gt;</span>
                                    @product<span class="token punctuation">.</span>Stock units
                                <span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">&gt;</span>
                            <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
                        <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
                    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
                <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"card-footer"</span><span class="token operator">&gt;</span>
                <span class="token operator">&lt;</span>TelerikButton OnClick<span class="token operator">=</span><span class="token string">"GoBack"</span>
                               ThemeColor<span class="token operator">=</span><span class="token string">"@ThemeConstants.Button.ThemeColor.Primary"</span><span class="token operator">&gt;</span>
                    <span class="token operator">&amp;</span>larr<span class="token punctuation">;</span> Back to Products
                <span class="token operator">&lt;</span><span class="token operator">/</span>TelerikButton<span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
<span class="token punctuation">}</span>

@code <span class="token punctuation">{</span>
    <span class="token punctuation">[</span>Parameter<span class="token punctuation">]</span>
    <span class="token keyword">public</span> <span class="token keyword">int</span> Id <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token keyword">private</span> Product<span class="token operator">?</span> product<span class="token punctuation">;</span>

    <span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token keyword">void</span> <span class="token function">OnInitialized</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token comment">// 1.</span>
        Navigation<span class="token punctuation">.</span>OnNotFound <span class="token operator">+</span><span class="token operator">=</span> HandleNotFound<span class="token punctuation">;</span>

        <span class="token comment">// 2.</span>
        product <span class="token operator">=</span> ProductService<span class="token punctuation">.</span><span class="token function">GetProductById</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>product <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token comment">// 3.            </span>
            Navigation<span class="token punctuation">.</span><span class="token function">NotFound</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">private</span> <span class="token keyword">void</span> <span class="token function">HandleNotFound</span><span class="token punctuation">(</span><span class="token keyword">object</span><span class="token operator">?</span> sender<span class="token punctuation">,</span> NotFoundEventArgs e<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token comment">// 4.</span>
        NotFoundContext<span class="token punctuation">.</span><span class="token function">UpdateContext</span><span class="token punctuation">(</span>
            <span class="token string">"Product Not Found"</span><span class="token punctuation">,</span>
            $<span class="token string">"The product with ID {Id} does not exist in our catalog."</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 keyword">void</span> <span class="token function">GoBack</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        Navigation<span class="token punctuation">.</span><span class="token function">NavigateTo</span><span class="token punctuation">(</span><span class="token string">"/products"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">Dispose</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token comment">// 5.</span>
        Navigation<span class="token punctuation">.</span>OnNotFound <span class="token operator">-</span><span class="token operator">=</span> HandleNotFound<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Let&rsquo;s analyze in more detail what happens in the code above:</p><ol><li>We subscribe to <code>Navigation.OnNotFound</code> to monitor when a product is not found.</li><li>The product is searched by its ID.</li><li>If the product does not exist, <code>Navigation.NotFound</code> is invoked, allowing the rendering of the component with an HTTP 404 code.</li><li>In the <code>HandleNotFound</code> handler, we set a custom title and message.</li><li>We unsubscribe from the event to avoid memory leaks.</li></ol><p>With the previous implementation, if we navigate to a nonexistent URL such as https://localhost:7038/not-found-page, a generic message will be displayed:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/generic-message-custom-component.png?sfvrsn=1642c57c_2" alt="Generic message displayed by the custom component" /></p><p>However, when trying to access the URL of a nonexistent product such as https://localhost:7038/product/122, we will find a custom message:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/custom-message-custom-component.png?sfvrsn=27ee4062_2" alt="Custom message rendered through a personalized component" /></p><p>With the above, we have confirmed that it is now much easier to handle not found routes.</p><h3 id="improvements-in-url-detection-using-navlinkmatch.all">Improvements in URL Detection using NavLinkMatch.All</h3><p>Before .NET 10, when using <code>Match="NavLinkMatch.All"</code>, Blazor was very strict in detecting links. For example, suppose you had something like this in your navigation menu:</p><p><code>&lt;NavLink href="https://www.telerik.comproducts" Match="NavLinkMatch.All"&gt;Products&lt;/NavLink&gt;</code></p><p>If you visited the <code>/products</code> page, the UI would mark an active link in the menu. However, if you navigated to a different URL such as <code>/products?price=cheap</code> or <code>/products#offers</code>, the UI would mark the section as inactive, leading to a poor user experience. This behavior is currently happening in our application:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/navigation-url-change-focus-loss.gif?sfvrsn=5b397a86_2" alt="Focus loss during navigation URL change" /></p><p>In the image above, you can see how the focus is lost when navigating to a product details page. This happens because the main URL is <code>http://localhost:5084/products</code>, while the product URL looks like this: <code>http://localhost:5084/product/2</code>.</p><p>Fortunately, in .NET 10 we can inherit from <code>NavLink</code> and write custom logic to handle matching the URLs we need:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CustomNavLink</span> <span class="token punctuation">:</span> NavLink
<span class="token punctuation">{</span>
    <span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token keyword">bool</span> <span class="token function">ShouldMatch</span><span class="token punctuation">(</span><span class="token keyword">string</span> currentUriAbsolute<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token comment">// 1.</span>
        <span class="token keyword">var</span> baseUri <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Uri</span><span class="token punctuation">(</span>NavigationManagerBase<span class="token punctuation">.</span>BaseUri<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">var</span> currentUri <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Uri</span><span class="token punctuation">(</span>currentUriAbsolute<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">var</span> relativePath <span class="token operator">=</span> currentUri<span class="token punctuation">.</span>AbsolutePath<span class="token punctuation">.</span><span class="token function">TrimStart</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ToLowerInvariant</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 2.</span>
        <span class="token keyword">var</span> href <span class="token operator">=</span> AdditionalAttributes <span class="token operator">!=</span> <span class="token keyword">null</span>
            <span class="token operator">&amp;&amp;</span> AdditionalAttributes<span class="token punctuation">.</span><span class="token function">TryGetValue</span><span class="token punctuation">(</span><span class="token string">"href"</span><span class="token punctuation">,</span> <span class="token keyword">out</span> <span class="token keyword">var</span> hrefValue<span class="token punctuation">)</span>
            <span class="token operator">?</span> hrefValue<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">TrimStart</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ToLowerInvariant</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 keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>href<span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token keyword">return</span> <span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">ShouldMatch</span><span class="token punctuation">(</span>currentUriAbsolute<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 3.</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>href <span class="token operator">==</span> <span class="token string">"products"</span><span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">return</span> relativePath <span class="token operator">==</span> <span class="token string">"products"</span>
                <span class="token operator">||</span> relativePath<span class="token punctuation">.</span><span class="token function">StartsWith</span><span class="token punctuation">(</span><span class="token string">"product/"</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 keyword">base</span><span class="token punctuation">.</span><span class="token function">ShouldMatch</span><span class="token punctuation">(</span>currentUriAbsolute<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token punctuation">[</span>Inject<span class="token punctuation">]</span>
    <span class="token keyword">private</span> NavigationManager NavigationManagerBase <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">default</span><span class="token operator">!</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>In the code above:</p><ol><li>We obtain the relative path from the absolute URI.</li><li>We get the href.</li><li>We perform a custom match so that <code>NavLink</code> is active both in <code>/products</code> and <code>/product/{id}</code>.</li></ol><p>For the previous implementation to work in the project, we need to swap <code>NavLink</code> for <code>CustomNavLink</code> in <code>NavMenu.razor</code>:</p><pre class=" language-xml"><code class="prism  language-xml">...
<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>nav-item px-3<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>CustomNavLink</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>nav-link<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>products<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>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bi bi-bag-fill-nav-menu<span class="token punctuation">"</span></span> <span class="token attr-name">aria-hidden</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 punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> Products
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>CustomNavLink</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 result of the implementation is that the user knows at all times where they are, thanks to the implementation of a custom <code>NavLink</code>:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/custom-navlink-logic.gif?sfvrsn=7067cad3_2" alt="Implementing custom logic for the NavLink component" /></p><h2 id="conclusion">Conclusion</h2><p>Throughout this article, you have learned about some new features in .NET 10 that are particularly useful for handling routes.</p><p>This includes creating a context for managing information on an error page and how to use this context to show users specific error pages, in addition to an inheritance of NavLink to define custom rules for better navigation.</p><p>Undoubtedly, these new features were much needed in Blazor. Now it&rsquo;s your time to use them and create better user experiences utilizing them alongside Progress Telerik <a target="_blank" href="https://www.telerik.com/blazor-ui">components for Blazor</a>.</p><img src="https://feeds.telerik.com/link/23050/17334920.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:354321ce-fa28-42ad-be8e-5ef8fe72a13c</id>
    <title type="text">Loading UI/UX Patterns for AI Applications</title>
    <summary type="text">Give users appropriate loading feedback for the AI process going on. Here are some patterns aligned to the wait time, with implementation ideas for Blazor.</summary>
    <published>2026-04-28T16:39:10Z</published>
    <updated>2026-06-14T09:54:16Z</updated>
    <author>
      <name>Ed Charbeneau </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23050/17327232/loading-ui-ux-patterns-ai-applications"/>
    <content type="text"><![CDATA[<p><span class="featured">Give users appropriate loading feedback for the AI process going on. Here are some patterns aligned to the wait time, with implementation ideas for Blazor.</span></p><p>AI-driven applications introduce a new set of challenges for user experience design. Traditional web applications operate within predictable boundaries, where requests complete in a consistent and measurable way. AI features change that dynamic, with response times ranging from near-instant to long-running operations that can take minutes. Designing for that variability is no longer optional, it is a core part of building reliable AI-powered applications.</p><p>The challenge extends beyond implementation into perception. Users do not experience time objectively; they react to how it feels. A blank screen creates doubt, while visible progress keeps the experience grounded. When feedback aligns with the effort required, the interaction feels natural. When it does not, friction builds quickly. Thoughtful loading design addresses this gap by communicating progress, setting expectations and reinforcing the value of the task in motion.</p><p>This guide focuses on practical loading UI patterns for AI scenarios, organized by real-world wait times. Each pattern is implemented with <a target="_blank" href="https://www.telerik.com/blazor-ui">Blazor and Progress Telerik UI components</a>, keeping the discussion grounded in tools developers already use. The goal is simple: create loading experiences that do more than fill time, improving perceived performance and building confidence in the system behind the scenes.
</p><h2>Understanding AI Application Loading Patterns</h2><p>AI applications introduce a different class of loading behavior. Traditional web requests are relatively predictable, but AI workloads are not. Inference, natural language processing and computer vision all introduce variability based on model complexity, input size and system load. As powerful as these capabilities are, they require a more deliberate approach to how progress is communicated.</p><p>Effective loading experiences center on managing expectations through clear, continuous feedback. Every loading state should communicate what is happening now, what has completed and what comes next, keeping users oriented as the system works. With this foundation in place, loading patterns can be tailored to specific wait times, keeping the experience responsive and understandable regardless of how long processing takes.</p><h2>Near Instantaneous Responses (Less Than 1 Second)</h2><p>For interactions under one second, traditional loading indicators often add more friction than value. Quick flashes of spinners or progress bars create a visual glitch that feels broken rather than helpful. Instead, the interface should respond immediately with subtle visual feedback that confirms the action without interrupting flow.</p><p>One exception stands out: when a fast action represents the final step in a longer workflow. In these cases, introducing a brief, intentional delay can create a sense of completion, giving users a moment to recognize the result of their effort before moving on.</p><h3>AI Task Examples</h3><p>AI tasks that typically complete in under one second include:</p><ul><li>Real-time text suggestions and autocomplete</li><li>Simple sentiment analysis on short text</li><li>Basic image classification with lightweight models</li><li>Cached AI responses</li><li>Rule-based chatbot responses</li><li>Simple recommendation filtering</li></ul><h3>Blazor Implementation Strategy</h3><p>Implementing instantaneous feedback in Blazor requires careful coordination between state changes and visual cues. The goal is to reflect user actions immediately while avoiding flicker from overly brief loading states. In practice, this often means enforcing a minimal display duration for indicators so that interactions feel smooth and intentional. </p><p>Try the A/B samples below by clicking the &ldquo;Zoom and Enhance&rdquo; buttons twice. The A sample should feel smoother on short intervals because of the intentional delay.</p><iframe width="100%" height="500px" src="https://blazorrepl.telerik.com/repl/embed/mAkScmvQ58rIAkuM38?editor=true&amp;result=true&amp;errorList=false"></iframe><h3>UX Strategy</h3><p>Instant interactions benefit from confirmation rather than explanation. Subtle cues like button state changes, input highlighting or lightweight animations signal that the system has responded, keeping the experience fluid and uninterrupted. When these signals are consistent and immediate, users stay oriented without feeling like they are waiting.</p><h2>Short Wait Times (1&ndash;3 Seconds)</h2><p>Short waits call for lightweight, indeterminate indicators that acknowledge progress without interrupting flow. Simple spinners or skeleton screens work well because they provide immediate feedback while keeping the interface responsive. More elaborate animations tend to work against this, as users do not have enough time to process them and the interaction can feel slower than it is.</p><p>Skeleton screens are especially effective in AI scenarios because they establish structure upfront. By rendering a placeholder version of the final layout, the interface maintains continuity and gives users a clear sense of what is coming next as content is generated.</p><h3>AI Task Examples</h3><p>AI operations in the 1&ndash;3 second range include:</p><ul><li>Text generation for short responses</li><li>Image enhancement or basic filtering</li><li>Summarizing a document of moderate length</li><li>Translation of short to medium text</li><li>Basic data analysis and insights generation</li><li>Voice-to-text conversion for brief audio</li></ul><h3>Blazor Implementation Strategy</h3><h4>Chat Progress and Thinking</h4><p>The Telerik UI for&nbsp;<a href="https://www.telerik.com/blazor-ui/skeleton" target="_blank">Blazor Skeleton</a> component provides a straightforward way to mirror final layouts while AI-generated content is loading and the agent is thinking.</p><iframe width="100%" height="500px" src="https://blazorrepl.telerik.com/repl/embed/wqkymwFI34Q3Bj4H27?editor=true&amp;result=true&amp;errorList=false"></iframe><h4>Smart Paste Loading</h4><p>The following demo shows a <a href="https://www.telerik.com/blazor-ui/smartpastebutton" target="_blank">smart paste interaction</a> that incorporates loading indicators to signal the process taking place. The Loading Container is displayed over the form fields being populated, while a button loader indicates the action is taking place once the button is clicked.</p><iframe width="100%" height="500px" src="https://blazorrepl.telerik.com/repl/embed/mquemabj125i6dVw38?editor=true&amp;result=true&amp;errorList=false"></iframe><h3>UX Strategy</h3><p>Short waits benefit from clarity without added friction. Contextual messaging that reflects the task in progress, such as &ldquo;Thinking&rdquo; or &ldquo;Generating recommendations,&rdquo; helps users understand what is happening without slowing the experience down. When combined with progressive disclosure, where partial results are rendered as they become available, the interface stays active and responsive, reducing perceived wait time while making the system&rsquo;s work visible.</p><h2>Medium Wait Times (3&ndash;10 Seconds)</h2><p>Users begin to question responsiveness, and a lack of visible progress quickly turns into doubt. Multi-agent workflows or agentic workflows with multiple indeterminate steps can be difficult to navigate. Agents can make requests to external tools that have asynchronous processes. While these processes run, it is important to report the activity in a manageable way without losing focus of the main content.</p><h3>Blazor Implementation</h3><p>Provide feedback for AI operations that expose measurable progress. The example below shows a chat process where the agent uses external tools. Loading indicators are exposed in a collapsible panel to allow the user to see the progress but also hide it when the details are no longer necessary.</p><iframe width="100%" height="500px" src="https://blazorrepl.telerik.com/repl/embed/QqEoGwvA09jzuqBe29?editor=true&amp;result=true&amp;errorList=false"></iframe><h3>UX Strategy</h3><p>Medium waits benefit from a balance of clarity and momentum. Directional time estimates, even something as simple as &ldquo;This may take about a minute,&rdquo; help users decide whether to stay engaged or return later, while continuously moving progress indicators reinforce that the system is still working. When paired with contextual messaging that explains the current step or highlights what is being processed, the experience shifts from passive waiting to a guided interaction that keeps users oriented and informed.</p><h2>Extended Wait Times (10+ Seconds)</h2><p>Extended wait times require a different approach. Clear visibility into progress matters, but so does the freedom to move on without losing track of what is happening. Combining progress indicators with background processing patterns allows the system to stay transparent while keeping the rest of the application usable.</p><p>Percent-complete indicators play a central role here by giving users a sense of scale. Seeing measurable progress helps them judge how much work remains and whether it is worth continuing to wait. At the same time, providing cancel or abort options keeps users in control rather than locked into a long-running process.</p><p>Step-based indicators work especially well for multi-stage AI operations by breaking the process into clear, understandable phases. Even when exact timing is uncertain, each completed step provides direction and reinforces forward movement.</p><h3>Blazor Implementation</h3><p>The following example uses a <a href="https://www.telerik.com/blazor-ui/grid" target="_blank">grid</a> format to display and manage agent activity. Each element displays important information about the task&rsquo;s state. In addition, failure modes are included and made actionable from the interface. This type of UX is great for dashboard-like scenarios where users can launch agent workflows and return later to see the task completion status.</p><iframe width="100%" height="500px" src="https://blazorrepl.telerik.com/repl/embed/QKOSGwlH59MIvvBw27?editor=true&amp;result=true&amp;errorList=false"></iframe><p>If the user may encounter a long and undetermined loading state, a looping indicator can be used to communicate the overall steps that are running in the background, without labeling exactly what stage the process is at now. This nondeterministic progress indicator displays a carousel of information while the user waits. </p><p>With agentic applications, long processes can give the impression of wasted time, even though a process that takes minutes for an agent may have taken a human hour to complete manually. This loading pattern reminds users of the work going on behind the scenes.&nbsp;While some consider this a &ldquo;dark pattern&rdquo; when used to obscure the process details, it can be quite useful when used correctly to share honest information about the value the process provides.</p><p><iframe width="100%" height="500px" src="https://blazorrepl.telerik.com/repl/embed/GKkImcbe33AOXWRF16?editor=true&amp;result=true&amp;errorList=false">&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;nbsp;</iframe></p><p>Extended waits benefit from a design that prioritizes flexibility and user control. Background task patterns, such as persistent status panels or drawers, allow users to continue working while keeping progress visible, reducing the friction of being forced to wait in place. When paired with notification systems that signal completion, the need to actively monitor progress is removed entirely, giving users confidence that the system will follow through.</p><p>Longer waits create space to surface meaningful insights, explain processing steps or provide guidance for improving future results. When these elements are combined effectively, the experience shifts from a blocking delay to a managed, transparent process that keeps users informed without interrupting their workflow.</p><h2>Advanced Patterns for AI Applications</h2><h3>Contextual Loading Messages</h3><p>AI applications benefit from contextual loading messages that explain current processing steps. Replace generic &ldquo;Loading...&rdquo; text with specific descriptions: &ldquo;Analyzing image composition,&rdquo; &ldquo;Generating creative variations&rdquo; or &ldquo;Cross-referencing knowledge base.&rdquo; These messages build user understanding of AI capabilities while setting realistic expectations for output quality.</p><h3>Streaming and Incremental Results</h3><p>Many modern AI applications support streaming responses, particularly for text generation. Implement progressive disclosure patterns that display AI outputs as they generate, reducing perceived wait time while demonstrating active processing. This approach works particularly well for conversational AI interfaces and content-generation tools.</p><h2>Summary</h2><p>Designing loading experiences for AI applications is no longer about handling delays. It is about shaping how users understand and interact with the system. When feedback aligns with the work being performed, users stay engaged and in control regardless of how long processing takes.</p><p>By matching loading strategies to expected wait times, developers can move beyond generic indicators and deliver feedback that is intentional and informative. From immediate visual confirmation to multi-stage progress tracking, each pattern helps make AI interactions feel predictable and responsive.</p><p>Blazor and Telerik UI components provide a practical foundation for implementing these patterns, enabling teams to build consistent loading experiences without introducing unnecessary complexity. The advantage comes from how these tools are applied, not just their availability.</p><p>As AI continues to shape modern applications, loading design becomes a defining part of the user experience. Applications that communicate clearly during processing will feel faster and more reliable, regardless of the work happening behind the scenes.</p><h3>Get Started with These Examples</h3><p>Use any of the Telerik UI for <a target="_blank" href="https://www.telerik.com/blazor-ui">Blazor components</a> shown above, plus the <a target="_blank" href="https://www.telerik.com/blazor-mcp-servers">Blazor MCP servers</a> free with the 30-day trial.</p><p><a href="https://www.telerik.com/try/ui-for-blazor" target="_blank" class="Btn">Try Now</a></p><img src="https://feeds.telerik.com/link/23050/17327232.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:e67bd1e0-6dce-4ba4-92de-7c7975a18492</id>
    <title type="text">Blazor Basics: Getting Started with Blazor Development in VS Code</title>
    <summary type="text">Learn how to use Visual Studio Code for Blazor web development. VS Code is a free, lightweight code editor, and it is available for Mac and Linux users (unlike its more robust sibling Visual Studio, which is exclusive to Windows).</summary>
    <published>2026-04-21T16:22:45Z</published>
    <updated>2026-06-14T09:54:16Z</updated>
    <author>
      <name>Claudio Bernasconi </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23050/17323034/blazor-basics-getting-started-blazor-development-vs-code"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn how to use Visual Studio Code for Blazor web development. VS Code is a free, lightweight code editor, and it is available for Mac and Linux users (unlike its more robust sibling Visual Studio, which is exclusive to Windows).</span></p><p>While many developers using Windows love the fully integrated development experience Visual Studio provides, it&rsquo;s not an option for some of us.</p><p>We will learn how to set up Visual Studio Code for Blazor web application development, a few first-hand tips and how to conveniently debug.</p><h2 id="why-use-visual-studio-code-for-blazor-web-development">Why Use Visual Studio Code for Blazor Web Development?</h2><p>Maybe you or your team already use <a target="_blank" href="https://code.visualstudio.com/">Visual Studio Code</a> for software development because of its excellent code editor or GIT integration. Why learn something new if you are happy with what you already have?</p><p>Another reason that comes to mind is your preferred operating system.</p><p><a target="_blank" href="https://visualstudio.microsoft.com/">Visual Studio</a> is only available for <strong>Windows</strong>. While I am a Windows user and have always loved the fully fledged feature set provided by Visual Studio for .NET development, I understand that there are other options.</p><p>For <strong>macOS</strong> or <strong>Linux</strong>, you do not have the option to use Visual Studio. Visual Studio Code (VS Code) is a great, lightweight, and free alternative.</p><p>Also, licensing can be an issue. While the Visual Studio Community edition has limitations, VS Code is free for .NET development, both personal and commercial.</p><p>Last but not least, VS Code uses less RAM, hard-drive space and CPU compared to fully fledged IDEs, such as Visual Studio. For hardware constraint situations, it&rsquo;s an ideal choice.</p><h2 id="getting-started-the-setup">Getting Started: The Setup</h2><p>We need two essential things before we can start developing Blazor web applications with VS Code.</p><ol><li>Obviously, we need the latest <a target="_blank" href="https://code.visualstudio.com/">Visual Studio Code</a> version installed</li><li>We also need the <a target="_blank" href="https://dotnet.microsoft.com/">latest .NET SDK</a> installed</li></ol><p>Make sure you can execute the <code>dotnet --version</code> command in a terminal. If it doesn&rsquo;t show the version of the installed <strong>.NET SDK</strong>, add the <strong>.NET CLI</strong> to the <code>PATH</code> variable of your operating system and restart your computer before trying again.</p><h2 id="installing-the-c-dev-kit">Installing the C# Dev Kit</h2><p>Next, we want to install the <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit">C# Dev Kit extension</a> for Visual Studio Code.</p><p><img title="C# Dev Kit Visual Studio Code extension" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/csharp-dev-kit-extension.png?sfvrsn=55b57e85_2" alt="The marketplace page of the C# Dev Kit Visual Studio Code extension." /></p><p>This extension adds C# development features, including project and solution management, debugging, syntax highlighting, code navigation, refactorings and more, to VS Code. It&rsquo;s a mature extension with more than 13 million downloads.</p><blockquote><p><strong>Hint:</strong> The C# Dev Kit extension not only adds support for Blazor web development but for all C# project types, including desktop, mobile, web, or cloud-native applications.</p></blockquote><h2 id="creating-a-blazor-web-app-in-vs-code">Creating a Blazor Web App in VS Code</h2><p>If you open an empty VS Code instance, you&rsquo;ll get the Create .NET Project menu option in the Explorer panel.</p><p><img title="Visual Studio Code: Explorer" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/explorer-create-new-dotnet-project.png?sfvrsn=7487329a_2" alt="The Explorer panel in Visual Studio Code in an empty project shows the Create .NET Project button." /></p><p>Pressing the <strong>Create .NET Project</strong> button will execute a VS Code command that allows you to select the project type. We select the default <strong>Blazor Web App</strong> project template and choose the destination folder on the hard drive.</p><p>Depending on the project template you choose, you&rsquo;ll be able to add additional information to influence the outcome of the created project.</p><p>After a few seconds, the Explorer now shows the project folder containing the created solution file, the project file and the <code>Components</code> folder containing the example pages and layouts.</p><p><img title="VS Code: Explorer" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/visual-studio-code-solution-explorer.png?sfvrsn=72c36ed7_2" alt="The Explorer panel in VS Code in a Blazor Web App shows the folders, such as the Components folder and all the required code files." /></p><blockquote><p><strong>Hint:</strong> We won&rsquo;t explore the structure and architecture of the Blazor Web application.</p></blockquote><p>Another option for creating a .NET project is using the .NET CLI from the terminal. The <code>dotnet new blazor</code> command creates the same project as shown above.</p><h2 id="running-the-blazor-web-application-in-vs-code">Running the Blazor Web Application in VS Code</h2><p>Running a Blazor Web Application is no different from running any other .NET-based application. In a terminal, you can use the <code>dotnet run</code> or <code>dotnet watch run</code> command to run it.</p><p>The <code>dotnet watch run</code> command automatically rebuilds and refreshes the browser (hot reload) when you edit the code and save the file.</p><p><img title="VS Code: Running a Blazor Web App" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/dotnet-watch-run-command.png?sfvrsn=94413184_2" alt="A terminal executing the dotnet watch run command in the folder of a Blazor Web App." /></p><p>The application runs the same whether you run it in Visual Studio or from the command line without VS Code. All three options use the .NET CLI under the hood.</p><p>Compared to Visual Studio, VS Code is noticeably faster at applying simple changes to components, such as the text of the default Home page component.</p><blockquote><p><strong>Tip:</strong> Using hot reload saves a lot of time. Use the <code>dotnet watch run</code> command and open the <code>Counter.razor</code> component. Change the code in the <code>IncrementCount</code> method from <code>currentCount++</code> to <code>currentCount+=2</code> and save the file. Whenever you hit the <strong>Click Me</strong> button, the counter now increases the value by <strong>two</strong> instead of <strong>one</strong>.</p></blockquote><h2 id="debugging-c-code-in-vs-code">Debugging C# Code in VS Code</h2><p>VS Code not only supports running the Blazor web app, but also debugging it.</p><p>To enable debugging:</p><ol><li>Open the <strong>Run and Debug</strong> panel (CTRL+SHIFT+D)</li><li>Click the <strong>Run and Debug</strong> button.</li><li>Select <strong>C#</strong></li><li>Select one of the available project options, or <strong>launch the Startup</strong> project.</li><li>Click on <strong>Start Debugging</strong> (Green Triangle), or press <strong>F5</strong>.</li></ol><p>You can click left of any C# code line to add a breakpoint. A yellow background highlights the code line when the debugger stops the execution. And you can use the toolbar to step through your code and hover over variables to see their values.</p><p><img title="VS Code: Debugging a Blazor Web App" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/debugging-blazor-web-app.png?sfvrsn=dfa894d3_2" alt="The VS Code debugger stopping at a code line and showing the local variables and the toolbar to control the program execution." /></p><p>The debugging experience is comparable to that of other fully fledged IDEs and allows you to find bugs and understand code execution.</p><p>You can add variables to the watch view to keep their values visible as you step through program execution. You also see the call stack whenever the program execution halts, and you can enable or disable the breakpoints.</p><blockquote><p><strong>Hint:</strong> Make sure the application isn&rsquo;t running from a terminal, such as using the dotnet watch run command.</p></blockquote><h2 id="conclusion">Conclusion</h2><p>While I personally prefer using Visual Studio 2026 for most of my development work, I hopefully was able to have shown that Visual Studio Code also offers a first-class development environment.</p><p>For Linux or macOS, VS Code would definitely be my first choice because it provides most of the tools I regularly use and contains much less bloat than a fully fledged IDE. VS Code is free for personal and commercial use.</p><p>Depending on the scope of your project and how you want to work, VS Code is a good choice to get started with Blazor web development. Especially if you already use VS Code for other projects, such as React or Angular web application development.</p><p>If you want to learn more about Blazor development, watch my <a target="_blank" href="https://www.youtube.com/playlist?list=PLwISgxnkpZGL_LhTQCWwp-WCzupv7lcp0">free Blazor Crash Course</a> on YouTube. And stay tuned to the Telerik blog for more <a target="_blank" href="https://www.telerik.com/blogs/tag/blazor-basics">Blazor Basics</a>.</p><img src="https://feeds.telerik.com/link/23050/17323034.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-06-14T09:54:16Z</updated>
    <author>
      <name>Hassan Djirdeh </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23050/17315934/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://d585tldpucybw.cloudfront.net/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://d585tldpucybw.cloudfront.net/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://d585tldpucybw.cloudfront.net/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://d585tldpucybw.cloudfront.net/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://d585tldpucybw.cloudfront.net/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://d585tldpucybw.cloudfront.net/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://d585tldpucybw.cloudfront.net/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/23050/17315934.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:d364128b-f493-4804-8555-fe37bca196fa</id>
    <title type="text">Blazor Basics: Building Responsive Blazor Apps with CSS Media Queries</title>
    <summary type="text">Responsive design is the reason applications feel polished and user-friendly. Learn how to build responsive Blazor web applications using CSS media queries.</summary>
    <published>2026-04-06T20:25:23Z</published>
    <updated>2026-06-14T09:54:16Z</updated>
    <author>
      <name>Claudio Bernasconi </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23050/17314707/blazor-basics-building-responsive-blazor-apps-css-media-queries"/>
    <content type="text"><![CDATA[<p><span class="featured">Responsive design is the reason applications feel polished and user-friendly. Learn how to build responsive Blazor web applications using CSS media queries.</span></p><p>Today, we will learn how to build responsive Blazor web applications. Responsive design is the reason applications feel polished and user-friendly.</p><p>We will first learn the basics of responsive design and how to use CSS media queries to implement responsive layouts. Next, we will learn about what we should and should not do in our Blazor logic (C# code).</p><p>You can <a target="_blank" href="https://github.com/claudiobernasconi/BlazorMediaQueries">access the code used in this example on GitHub</a>.</p><h2 id="what-is-responsive-design-for-blazor-apps">What Is Responsive Design for Blazor Apps?</h2><p>Blazor provides a user interface rendering engine (Razor components) that lets us implement behavior using C#. Blazor components consist of an HTML and CSS template combined with C# interaction logic.</p><p>In modern web development, we want to utilize <strong>CSS media queries</strong> to let our web applications adapt to different screen sizes:</p><ul><li>Small screens, such as mobile phones</li><li>Medium screens, such as tablets</li><li>Large screens, such as desktop computers</li><li>(optional) Ultra-wide monitors</li></ul><p>Best practices for general web development also apply to implementing Blazor web applications.</p><h2 id="css-media-queries-in-blazor-components">CSS Media Queries in Blazor Components</h2><p>Let&rsquo;s learn about <strong>CSS media queries</strong> using a practical example, a Blazor web application generated from the .NET 10 Blazor Web App project template.</p><p>The <code>NavMenu</code> component contains a menu toggler. How it appears on the screen differs completely between a larger and a smaller screen.</p><p><img title="Blazor Web App: No Nav Button" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/nav-button-not-visible-on-desktop.png?sfvrsn=257d381_2" alt="A browser with a running Blazor web appliation on desktop. The nav button is not visible." /></p><p>For a larger screen, the menu is always visible on the left. For a smaller screen, the menu is collapsed, and the menu toggler is visible. The menu only appears if the user presses the hamburger menu button.</p><p>The HTML definition in the <code>NavMenu</code> component looks like this:</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>checkbox<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>Navigation menu<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>navbar-toggler<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
</code></pre><p>It&rsquo;s an input element with the <code>navbar-toggler</code> CSS class attached.</p><p>Let&rsquo;s look at the CSS code defining that behavior:</p><pre class=" language-css"><code class="prism  language-css"><span class="token selector"><span class="token class">.navbar-toggler</span> </span><span class="token punctuation">{</span>
    <span class="token property">appearance</span><span class="token punctuation">:</span> none<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 property">width</span><span class="token punctuation">:</span> <span class="token number">3.5</span>rem<span class="token punctuation">;</span>
    <span class="token property">height</span><span class="token punctuation">:</span> <span class="token number">2.5</span>rem<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 property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span>
    <span class="token property">top</span><span class="token punctuation">:</span> <span class="token number">0.5</span>rem<span class="token punctuation">;</span>
    <span class="token property">right</span><span class="token punctuation">:</span> <span class="token number">1</span>rem<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 function">rgba</span><span class="token punctuation">(</span><span class="token number">255</span>, <span class="token number">255</span>, <span class="token number">255</span>, <span class="token number">0.1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">background</span><span class="token punctuation">:</span> <span class="token url">url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")</span> no-repeat center/<span class="token number">1.75</span>rem <span class="token function">rgba</span><span class="token punctuation">(</span><span class="token number">255</span>, <span class="token number">255</span>, <span class="token number">255</span>, <span class="token number">0.1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>This CSS class definition defines the visual appearance of the menu toggler. It includes an inline SVG to define the three horizontal lines and a few spacing definitions.</p><p>As shown in the image above, on larger screens, this nav menu button is not visible. Let&rsquo;s look at the CSS code that implements this behavior.</p><pre class=" language-css"><code class="prism  language-css"><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 641px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token selector"><span class="token class">.navbar-toggler</span> </span><span class="token punctuation">{</span>
        <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>The <code>@media</code> syntax introduces the <strong>CSS media query</strong> feature. In the parentheses, we can implement a filter. In this case, we want all CSS definitions placed inside the curly braces to apply in case the filter condition evaluates to true. In this case, the minimum width of the rendered web page is expected to be 641 pixels.</p><p>In other words: When the page is at least 641 pixels in width, we want the CSS definitions inside the curly braces to be applied. In this definition, we set the <code>display</code> property to <code>none</code> for the <code>navbar-toggler</code> CSS class.</p><p><strong>Learning:</strong> Using CSS media queries, we can implement conditional rules based on a filter criterion. For example, we can add additional CSS definitions for existing CSS classes.</p><p><strong>Hint:</strong> There are additional CSS definitions inside the <code>NavMenu.razor.css</code> file generated by the default .NET 10 Blazor Web App project template. For simplicity and illustration, I included only the relevant code.</p><h2 id="hiding-information-on-smaller-screens">Hiding Information on Smaller Screens</h2><p>A very useful technique is to show certain information only for larger screens.</p><p>As mentioned earlier, you want to carefully decide what information to show on the screen. Does it help the user with the current use case, or does it distract? Is it really necessary?</p><p>Consider the following screenshot of the Weather page for a desktop-sized screen.</p><p><img title="Blazor Web App: Weather Page with all columns" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/weather-page-all-columns-visible.png?sfvrsn=eff050a4_2" alt="A browser with a running Blazor web appliation on desktop. The weather page contains the Date, Temp. (C), Temp. (F), and Summary columns." /></p><p>We have data in four columns: Date, Temperature in Celsius, Temperature in Fahrenheit and Summary.</p><p>The Summary column adds a textual explanation and gives slightly more detail than the numerical temperature. Let&rsquo;s say we don&rsquo;t want to show that Summary on mobile to help the user focus on the actual temperature numbers.</p><p>Let&rsquo;s add the following class definition to the <code>th</code> and <code>td</code> elements of the table in the <code>Weather</code> page 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>th</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>desktop-only<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Summary<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>td</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>desktop-only<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@forecast.Summary<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>We added the desktop-only CSS class to those HTML elements.</p><p>Now, we implement the CSS code inside the <code>Weather.razor.css</code> file:</p><pre class=" language-css"><code class="prism  language-css"><span class="token selector"><span class="token class">.desktop-only</span> </span><span class="token punctuation">{</span>
    <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 768px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token selector"><span class="token class">.desktop-only</span> </span><span class="token punctuation">{</span>
        <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>We set the <code>display</code> property to <code>none</code> and implement a media query to set it to block for screens larger than 768 pixels.</p><p><img title="Blazor Web App: Weather Page with limited data" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/weather-page-summary-not-visible-on-mobile.png?sfvrsn=a130b019_2" alt="A browser with a running Blazor web appliation on mobile. The weather page contains the Date, Temp. (C), and Temp. (F) columns. The Summary column does not show up on mobile." /></p><p>As you can see in the image, the Summary column doesn&rsquo;t show up for mobile users.</p><p>This is a simple yet powerful technique for conditionally rendering information based on screen size without requiring imperative C# code, such as using the <code>@if</code> directive in the component&rsquo;s template.</p><h2 id="integrating-user-interface-control-libraries">Integrating User Interface Control Libraries</h2><p>You might think that using a professional user control library, such as Progress <a target="_blank" href="https://www.telerik.com/blazor-ui">Telerik UI for Blazor</a>, solves everything for you. They provide professional-looking, tested user interface controls with accessibility and usability in mind. They also provide theming support, making it easy to apply custom colors.</p><p>However, while those components are implemented with responsive design in mind internally, you still have to arrange the layout around them, show and hide panels, and adjust spacing or information density.</p><p>You need to understand the overall structure of your web application and know when to step in and adjust the page layout to accommodate the various aspect ratios and device sizes of the modern world&mdash;from a handheld smartphone to a large 34" desktop monitor.</p><p>A good example provides the implementation of the <code>MainLayout</code> page in the default .NET 10 Blazor Web App project template:</p><pre class=" language-css"><code class="prism  language-css"><span class="token selector"><span class="token class">.page</span> </span><span class="token punctuation">{</span>
    <span class="token property">position</span><span class="token punctuation">:</span> relative<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">flex-direction</span><span class="token punctuation">:</span> column<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 641px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token selector"><span class="token class">.page</span> </span><span class="token punctuation">{</span>
        <span class="token property">flex-direction</span><span class="token punctuation">:</span> row<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>The <code>page</code> CSS class is applied to the most outer <code>div</code> of the <code>MainLayout</code> component. It defines a relative position and a flex layout with the flex direction <code>column</code>. It means that the items will be rendered vertically below each other.</p><p>The following media query, with a minimum width of 641 pixels, sets the flex direction to <code>row</code>. It means that for screens at least 641 pixels wide, the items will be placed horizontally beside each other.</p><p><strong>This is an excellent example of how to utilize CSS media queries to structure your pages for different screen sizes.</strong></p><p>Yes, utilizing one of the proven user interface libraries will take a lot of weight off your shoulders and provide you with ready-to-use building blocks.</p><p>It will save you a lot of time and let you focus on solving your business problems rather than reinventing the wheel by implementing foundational components.</p><p>However, a fully responsive web application integrates those components to form a truly responsive web application.</p><p><strong>In short:</strong> Responsive design touches all levels of web application development. You have to consider it when implementing reusable building blocks, and when orchestrating them to form a page or application part.</p><h2 id="best-practices-for-implementing-responsive-blazor-web-applications">Best Practices for Implementing Responsive Blazor Web Applications</h2><p>The following best practices will help you with implementing your responsive Blazor web applications:</p><ol><li><strong>Use a mobile-first approach:</strong> When implementing page layouts, always start with the layout for the smallest screens. It will force you to clearly structure the information and present it in a user-friendly way. Creating the layouts for bigger screens is much simpler than starting with a big screen and trying to size it down.</li><li><strong>Use CSS Grid &amp; CSS Flexbox:</strong> They adapt naturally to screen changes, reducing the need for complex breakpoints and other complex CSS magic. I personally prefer Flexbox for internal component structure and Grid for layout.</li><li><strong>Use CSS Isolation in Blazor:</strong> Component-specific styles written in [Component].razor.css files are scoped and easily maintainable. You&rsquo;re sure that changes made in that file do not propagate to other components or your entire application code.</li><li><strong>Avoid screen-size logic in C#:</strong> Do not try to detect screen width or similar information from C# interaction code. Let CSS do the layouting and focus on loading, storing, updating and organizing data in your C# Code.</li><li><strong>Use the browser&rsquo;s developer tools:</strong> Test your responsive web app by changing resolutions and aspect ratios to simulate different devices.</li><li><strong>Use prebuilt user interface libraries:</strong> Reinventing the wheel is time-consuming, and you risk repeating mistakes others have already made and fixed. However, you still need to take care to properly integrate and arrange those third-party components to keep your web application fully responsive.</li></ol><h2 id="conclusion">Conclusion</h2><p>Blazor provides a powerful, simple user interface rendering engine. However, true responsiveness comes from combining it with modern CSS techniques, such as media queries.</p><p>Utilizing CSS Isolation will allow you to separate the scope of your CSS for individual components.</p><p>Responsive design is important for implementing modern low-level components, but also for integrating them into a full webpage or web application.</p><p>While CSS media queries are powerful and let us implement conditional behavior, it&rsquo;s still a lot of code that needs to be maintained. Be careful to extract reused code into components to minimize the effect, and use third-party user interface libraries to avoid re-inventing the wheel.</p><p>If you want to learn more about Blazor development, watch my <a target="_blank" href="https://www.youtube.com/playlist?list=PLwISgxnkpZGL_LhTQCWwp-WCzupv7lcp0">free Blazor Crash Course</a> on YouTube. And stay tuned to the Telerik blog for more <a target="_blank" href="https://www.telerik.com/blogs/tag/blazor-basics">Blazor Basics</a>.</p><img src="https://feeds.telerik.com/link/23050/17314707.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:fda2f92a-0bba-4092-b4a7-71adac14edf1</id>
    <title type="text">Instantiating Objects and Accessing Properties in Blazor</title>
    <summary type="text">Learn how to use Blazor’s interop features with JavaScript to handle live C# objects for typeable code.</summary>
    <published>2026-03-30T19:06:20Z</published>
    <updated>2026-06-14T09:54:16Z</updated>
    <author>
      <name>Héctor Pérez </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23050/17309760/instantiating-objects-accessing-properties-blazor"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn how to use Blazor&rsquo;s interop features with JavaScript to handle live C# objects for typeable code.</span></p><p>Blazor is Microsoft&rsquo;s framework ideal for creating single-page applications (SPAs), complementing the stack for developing applications entirely in .NET. This is why each year we see significant updates in the framework that allows developers to create secure and robust applications. These changes, along with <a target="_blank" href="https://www.telerik.com/blazor-ui">Blazor control suites</a>&nbsp;like the one from Progress Telerik, undoubtedly accelerate the development of complete apps.</p><p>In this article, I will tell you about the new interop features with JavaScript, which certainly marks a significant improvement in handling objects from the C# language. Let&rsquo;s get started!</p><h2 id="understanding-the-problem-to-solve">Understanding the Problem to Solve</h2><p>Until .NET 10, interoperability with JS was mainly done by invoking JS functions, without being able to directly handle live objects from C# code, which involved creating wrappers and code that could often lead to failures and runtime errors due to syntax errors.</p><p>We can get an idea of the above through a practical case. Suppose that in our application, we have a <a target="_blank" href="https://www.telerik.com/blazor-ui/gridhttps://demos.telerik.com/blazor-ui/grid/overview">Blazor Data Grid</a> control that allows displaying products from an online store. Each row has a column with a button to show a lightbox popup, where images are displayed. The demonstration code, for you to gain a complete idea, looks as follows.</p><p>First, I created a JavaScript file with the necessary functionality to display the lightbox image gallery:</p><p><strong>lightboxGallery.js</strong></p><pre class=" language-javascript"><code class="prism  language-javascript">window<span class="token punctuation">.</span>lightboxGallery <span class="token operator">=</span> <span class="token punctuation">{</span>
    LightboxGallery<span class="token punctuation">:</span> <span class="token keyword">class</span> <span class="token class-name">LightboxGallery</span> <span class="token punctuation">{</span>
        <span class="token function">constructor</span><span class="token punctuation">(</span>imageUrls<span class="token punctuation">,</span> startIndex <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>images <span class="token operator">=</span> imageUrls<span class="token punctuation">;</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>currentIndex <span class="token operator">=</span> startIndex<span class="token punctuation">;</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>overlayElement <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>keyHandler <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token function">show</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><span class="token function">createOverlay</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><span class="token function">displayImage</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">createOverlay</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 keyword">this</span><span class="token punctuation">.</span>overlayElement<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">this</span><span class="token punctuation">.</span>overlayElement<span class="token punctuation">.</span><span class="token function">remove</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>overlayElement <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>overlayElement<span class="token punctuation">.</span>className <span class="token operator">=</span> <span class="token string">'lightbox-overlay'</span><span class="token punctuation">;</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>overlayElement<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token template-string"><span class="token string">`
            &lt;div class="lightbox-container"&gt;
                &lt;button class="lightbox-close"&gt;&amp;times;&lt;/button&gt;
                &lt;button class="lightbox-prev"&gt;&amp;lsaquo;&lt;/button&gt;
                &lt;div class="lightbox-content"&gt;
                    &lt;img class="lightbox-image" src="https://www.telerik.com" alt="Gallery Image"&gt;
                    &lt;div class="lightbox-counter"&gt;&lt;/div&gt;
                &lt;/div&gt;
                &lt;button class="lightbox-next"&gt;&amp;rsaquo;&lt;/button&gt;
            &lt;/div&gt;
        `</span></span><span class="token punctuation">;</span>

            document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>overlayElement<span class="token punctuation">)</span><span class="token punctuation">;</span>
            
            <span class="token keyword">this</span><span class="token punctuation">.</span>overlayElement<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.lightbox-close'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</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">this</span><span class="token punctuation">.</span><span class="token function">close</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>overlayElement<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.lightbox-prev'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</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">this</span><span class="token punctuation">.</span><span class="token function">prev</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>overlayElement<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.lightbox-next'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</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">this</span><span class="token punctuation">.</span><span class="token function">next</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>overlayElement<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>e<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>e<span class="token punctuation">.</span>target <span class="token operator">===</span> <span class="token keyword">this</span><span class="token punctuation">.</span>overlayElement<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">close</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">this</span><span class="token punctuation">.</span><span class="token function-variable function">keyHandler</span> <span class="token operator">=</span> <span class="token punctuation">(</span>e<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>e<span class="token punctuation">.</span>key <span class="token operator">===</span> <span class="token string">'Escape'</span><span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">close</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>e<span class="token punctuation">.</span>key <span class="token operator">===</span> <span class="token string">'ArrowLeft'</span><span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">prev</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>e<span class="token punctuation">.</span>key <span class="token operator">===</span> <span class="token string">'ArrowRight'</span><span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">next</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>
            document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'keydown'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>keyHandler<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token function">displayImage</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><span class="token keyword">this</span><span class="token punctuation">.</span>overlayElement<span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>

            <span class="token keyword">const</span> img <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>overlayElement<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.lightbox-image'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">const</span> counter <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>overlayElement<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.lightbox-counter'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            img<span class="token punctuation">.</span>src <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>images<span class="token punctuation">[</span><span class="token keyword">this</span><span class="token punctuation">.</span>currentIndex<span class="token punctuation">]</span><span class="token punctuation">;</span>
            counter<span class="token punctuation">.</span>textContent <span class="token operator">=</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>currentIndex <span class="token operator">+</span> <span class="token number">1</span><span class="token interpolation-punctuation punctuation">}</span></span><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>images<span class="token punctuation">.</span>length<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 function">next</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>currentIndex <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>currentIndex <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">%</span> <span class="token keyword">this</span><span class="token punctuation">.</span>images<span class="token punctuation">.</span>length<span class="token punctuation">;</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">displayImage</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">prev</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>currentIndex <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>currentIndex <span class="token operator">-</span> <span class="token number">1</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>images<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token operator">%</span> <span class="token keyword">this</span><span class="token punctuation">.</span>images<span class="token punctuation">.</span>length<span class="token punctuation">;</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">displayImage</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">close</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 keyword">this</span><span class="token punctuation">.</span>overlayElement<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">this</span><span class="token punctuation">.</span>overlayElement<span class="token punctuation">.</span><span class="token function">remove</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>overlayElement <span class="token operator">=</span> <span class="token keyword">null</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 keyword">this</span><span class="token punctuation">.</span>keyHandler<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                document<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span><span class="token string">'keydown'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>keyHandler<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">this</span><span class="token punctuation">.</span>keyHandler <span class="token operator">=</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 function">getCurrentIndex</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 keyword">this</span><span class="token punctuation">.</span>currentIndex<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        
        <span class="token function">getImagesLength</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 keyword">this</span><span class="token punctuation">.</span>images<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 punctuation">;</span>
</code></pre><p>The above code shows the definition of a JS class <code>LightboxGallery</code> with some properties to control the gallery. In addition, methods are also defined to enable interaction with it, such as <code>next</code>, <code>prev</code>, <code>show</code>, etc.</p><p>This file needs to be registered in <code>App.razor</code> to be able to use it from the application, as I show you 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>head</span><span class="token punctuation">&gt;</span></span>
    ...
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Routes</span> <span class="token attr-name">@rendermode</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>InteractiveServer<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>ReconnectModal</span> <span class="token punctuation">/&gt;</span></span>
    &lt;script src="https://www.telerik.com@Assets["_content/Telerik.UI.for.Blazor/js/telerik-blazor.js"]"&gt;<span class="token script language-javascript"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
    &lt;script src="https://www.telerik.com@Assets["js/lightboxGallery.js"]"&gt;<span class="token script language-javascript"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
    &lt;script src="https://www.telerik.com@Assets["_framework/blazor.web.js"]"&gt;<span class="token script language-javascript"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Finally, I created a Razor page where I use the Blazor Data Grid and <a target="_blank" href="https://www.telerik.com/blazor-ui/buttons">Blazor Button</a> components to create a quick and functional graphic interface.</p><pre class=" language-xml"><code class="prism  language-xml">@page "/products-traditional"
@inject IJSRuntime JSRuntime

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>PageTitle</span><span class="token punctuation">&gt;</span></span>Products - Traditional JS Interop<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>PageTitle</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>container-fluid mt-4<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>row mb-4<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>col-12<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>h1</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>display-6<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Product Gallery<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>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>

    <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>row<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>col-12<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>TelerikGrid</span> <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@Products<span class="token punctuation">"</span></span>
                         <span class="token attr-name">Pageable</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">PageSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>10<span class="token punctuation">"</span></span>
                         <span class="token attr-name">Sortable</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">FilterMode</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@GridFilterMode.FilterRow<span class="token punctuation">"</span></span>
                         <span class="token attr-name">Resizable</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">Height</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>600px<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>GridColumns</span><span class="token punctuation">&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridColumn</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@nameof(Product.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>ID<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>80px<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>GridColumn</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@nameof(Product.Name)<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>Product Name<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>200px<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>GridColumn</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@nameof(Product.Category)<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>Category<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>150px<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>GridColumn</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@nameof(Product.Price)<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>Price<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>120px<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>Template</span><span class="token punctuation">&gt;</span></span>
                            @{
                                var product = context as Product;
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>$@product?.Price.ToString("N2")<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>Template</span><span class="token punctuation">&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>GridColumn</span><span class="token punctuation">&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridColumn</span> <span class="token attr-name">Field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@nameof(Product.Stock)<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>Stock<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>100px<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>GridColumn</span> <span class="token attr-name">Title</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 attr-name">Width</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>150px<span class="token punctuation">"</span></span> 
                                <span class="token attr-name">Filterable</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>false<span class="token punctuation">"</span></span> 
                                <span class="token attr-name">Sortable</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>false<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>Template</span><span class="token punctuation">&gt;</span></span>
                            @{
                                var product = context as Product;
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikButton</span> <span class="token attr-name">OnClick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@(async () =&gt; await ShowImagesTraditional(product))<span class="token punctuation">"</span></span>
                                               <span class="token attr-name">ThemeColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.Button.ThemeColor.Primary<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                                    Show Images
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikButton</span><span class="token punctuation">&gt;</span></span>
                            }
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Template</span><span class="token punctuation">&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>GridColumn</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>GridColumns</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikGrid</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>If we want to invoke the methods from the JS code, there are various ways, although in the following example I show you one of the easiest. To display the gallery, we would use the following code:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">private</span> <span class="token keyword">async</span> Task <span class="token function">ShowImagesTraditional</span><span class="token punctuation">(</span>Product<span class="token operator">?</span> product<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>product <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> product<span class="token punctuation">.</span>ImageUrls<span class="token punctuation">.</span>Count <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span>
        <span class="token keyword">return</span><span class="token punctuation">;</span>
        
    <span class="token keyword">var</span> imageUrlsJson <span class="token operator">=</span> System<span class="token punctuation">.</span>Text<span class="token punctuation">.</span>Json<span class="token punctuation">.</span>JsonSerializer<span class="token punctuation">.</span><span class="token function">Serialize</span><span class="token punctuation">(</span>product<span class="token punctuation">.</span>ImageUrls<span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    <span class="token comment">// Step 1</span>
    <span class="token keyword">await</span> JSRuntime<span class="token punctuation">.</span><span class="token function">InvokeVoidAsync</span><span class="token punctuation">(</span><span class="token string">"eval"</span><span class="token punctuation">,</span> 
        $<span class="token string">"window.__tempGallery = new lightboxGallery.LightboxGallery({imageUrlsJson}, 0)"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    <span class="token comment">// Step 2</span>
    <span class="token keyword">await</span> JSRuntime<span class="token punctuation">.</span><span class="token function">InvokeVoidAsync</span><span class="token punctuation">(</span><span class="token string">"eval"</span><span class="token punctuation">,</span> <span class="token string">"window.__tempGallery.show()"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    <span class="token comment">// Step 3</span>
    <span class="token keyword">var</span> currentIndex <span class="token operator">=</span> <span class="token keyword">await</span> JSRuntime<span class="token punctuation">.</span><span class="token generic-method function">InvokeAsync<span class="token punctuation">&lt;</span><span class="token keyword">int</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token string">"eval"</span><span class="token punctuation">,</span> <span class="token string">"window.__tempGallery.currentIndex"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    <span class="token comment">// Step 4</span>
    <span class="token keyword">var</span> imagesCount <span class="token operator">=</span> <span class="token keyword">await</span> JSRuntime<span class="token punctuation">.</span><span class="token generic-method function">InvokeAsync<span class="token punctuation">&lt;</span><span class="token keyword">int</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token string">"eval"</span><span class="token punctuation">,</span> <span class="token string">"window.__tempGallery.images.length"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    <span class="token comment">// Step 5</span>
    Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span>$<span class="token string">"Traditional: Showing {imagesCount} images, starting at index {currentIndex}"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    isGalleryOpen <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">;</span>
    <span class="token function">StateHasChanged</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    
<span class="token punctuation">}</span>
</code></pre><p>Here&rsquo;s what we do in the above code:</p><ul><li><strong>Step 1</strong>: We use eval and global variables in <code>window</code> to maintain the reference to the gallery.</li><li><strong>Step 2</strong>: The method show defined in the class <code>LightboxGallery</code> is called.</li><li><strong>Step 3</strong>: We obtain the <code>index</code> of the image from the gallery.</li><li><strong>Step 4</strong>: The number of images is obtained using <code>lenght</code>.</li><li><strong>Step 5</strong>: The results are displayed based on the information obtained.</li></ul><p>The same applies to perform operations like navigating forward or backward:</p><p><strong>Navigating Forward</strong></p><pre class=" language-javascript"><code class="prism  language-javascript"><span class="token keyword">await</span> JSRuntime<span class="token punctuation">.</span><span class="token function">InvokeVoidAsync</span><span class="token punctuation">(</span><span class="token string">"eval"</span><span class="token punctuation">,</span> <span class="token string">"window.__tempGallery.next()"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p><strong>Navigating Backward</strong></p><pre class=" language-javascript"><code class="prism  language-javascript"><span class="token keyword">await</span> JSRuntime<span class="token punctuation">.</span><span class="token function">InvokeVoidAsync</span><span class="token punctuation">(</span><span class="token string">"eval"</span><span class="token punctuation">,</span> <span class="token string">"window.__tempGallery.prev()"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Or even to close the gallery:</p><pre class=" language-javascript"><code class="prism  language-javascript"><span class="token keyword">await</span> JSRuntime<span class="token punctuation">.</span><span class="token function">InvokeVoidAsync</span><span class="token punctuation">(</span><span class="token string">"eval"</span><span class="token punctuation">,</span> <span class="token string">"window.__tempGallery.close()"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">await</span> JSRuntime<span class="token punctuation">.</span><span class="token function">InvokeVoidAsync</span><span class="token punctuation">(</span><span class="token string">"eval"</span><span class="token punctuation">,</span> <span class="token string">"delete window.__tempGallery"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The example being executed looks as follows:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/demo-app-js-gallery.gif?sfvrsn=466ae63b_2" alt="The demo application displaying a gallery rendered with JavaScript" /></p><p>In the previous example, you can notice several problems, starting with the use of <code>eval</code>, which allows executing text as JavaScript code. Although it is an easy way to run code, it poses a danger as it opens the door to code injection. Moreover, it is slow as it cannot be optimized, is difficult to debug and is generally considered a bad practice.</p><p>Another problem is the direct use of global variables in <code>window</code>, as there is a risk of collisions with other libraries in the project; there is no management of galleries or lifecycle, plus there is no control over when to destroy it.</p><p>A third serious problem is that there can be a memory leak if the object in memory isn&rsquo;t destroyed since the browser&rsquo;s garbage collection (GC) cannot collect the reference, leaving listeners and live DOM references.</p><h2 id="new-javascript-interop-features-in-blazor-10">New JavaScript Interop Features in Blazor 10</h2><p>We could continue discussing the multiple issues in the example from the previous section, but let&rsquo;s focus on the new features of Blazor in .NET 10 to address this.</p><h2 id="the-invokeconstructorasync-method">The InvokeConstructorAsync Method</h2><p>In .NET 10, it is possible to use the method <code>InvokeConstructorAsync</code>, which allows you to invoke a JS constructor asynchronously. This method will execute the <code>new</code> operator and return a type <code>IJSObjectReference</code>. For example, to display a gallery, it would be done as follows:</p><pre class=" language-csharp"><code class="prism  language-csharp">@code <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> IJSObjectReference<span class="token operator">?</span> galleryInstance<span class="token punctuation">;</span>
    <span class="token keyword">private</span> GalleryInfo<span class="token operator">?</span> currentGalleryInfo<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 keyword">async</span> Task <span class="token function">ShowImagesModern</span><span class="token punctuation">(</span>Product<span class="token operator">?</span> product<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>product <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> product<span class="token punctuation">.</span>ImageUrls<span class="token punctuation">.</span>Count <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>

        <span class="token keyword">try</span>
        <span class="token punctuation">{</span>            
            <span class="token keyword">if</span> <span class="token punctuation">(</span>galleryInstance <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
            <span class="token punctuation">{</span>
                <span class="token keyword">await</span> galleryInstance<span class="token punctuation">.</span><span class="token function">DisposeAsync</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">var</span> imageUrls <span class="token operator">=</span> product<span class="token punctuation">.</span>ImageUrls<span class="token punctuation">.</span><span class="token function">ToArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            
            <span class="token comment">// Step 1</span>
            galleryInstance <span class="token operator">=</span> <span class="token keyword">await</span> JSRuntime<span class="token punctuation">.</span><span class="token function">InvokeConstructorAsync</span><span class="token punctuation">(</span>
                <span class="token string">"lightboxGallery.LightboxGallery"</span><span class="token punctuation">,</span> 
                imageUrls<span class="token punctuation">,</span> 
                <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment">// Step 2</span>
            <span class="token keyword">await</span> galleryInstance<span class="token punctuation">.</span><span class="token function">InvokeVoidAsync</span><span class="token punctuation">(</span><span class="token string">"show"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment">// Step 3</span>
            <span class="token keyword">var</span> currentIndex <span class="token operator">=</span> <span class="token keyword">await</span> galleryInstance<span class="token punctuation">.</span><span class="token generic-method function">GetValueAsync<span class="token punctuation">&lt;</span><span class="token keyword">int</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token string">"currentIndex"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            
            <span class="token comment">// Step 4</span>
            <span class="token keyword">var</span> imagesLength <span class="token operator">=</span> <span class="token keyword">await</span> galleryInstance<span class="token punctuation">.</span><span class="token generic-method function">GetValueAsync<span class="token punctuation">&lt;</span><span class="token keyword">int</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token string">"images.length"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            
            <span class="token comment">//Step 5</span>
            currentGalleryInfo <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">GalleryInfo</span>
            <span class="token punctuation">{</span>
                CurrentIndex <span class="token operator">=</span> currentIndex<span class="token punctuation">,</span>
                TotalImages <span class="token operator">=</span> imagesLength
            <span class="token punctuation">}</span><span class="token punctuation">;</span>

            <span class="token function">StateHasChanged</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">WriteLine</span><span class="token punctuation">(</span>$<span class="token string">"Modern: Showing {imagesLength} images, starting at index {currentIndex}"</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><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span>$<span class="token string">"Error showing images: {ex.Message}"</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 above code, the exact same steps are followed to display the gallery, but with cleaner code. <code>InvokeConstructorAsync</code> is used to create the object and maintain its reference, which can in turn be used to invoke other methods using the traditional method <code>InvokeVoidAsync</code>. In our example, we invoke the method <code>show</code> defined in the JavaScript class.</p><p>To perform other actions, a similar approach is followed:</p><p>To advance:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">await</span> galleryInstance<span class="token punctuation">.</span><span class="token function">InvokeVoidAsync</span><span class="token punctuation">(</span><span class="token string">"next"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>To go back:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">await</span> galleryInstance<span class="token punctuation">.</span><span class="token function">InvokeVoidAsync</span><span class="token punctuation">(</span><span class="token string">"prev"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>To close the gallery:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">await</span> galleryInstance<span class="token punctuation">.</span><span class="token function">InvokeVoidAsync</span><span class="token punctuation">(</span><span class="token string">"close"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
currentGalleryInfo <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token function">StateHasChanged</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>With this new approach, we have a drastic change not only aesthetically but also internally. For example, each component has its own instance, which prevents collisions between them. Additionally, there is a controlled lifecycle with no memory leaks. You may also notice that parameter passing is much simpler and safer.</p><h2 id="the-getvalueasync-and-setvalueasync-methods">The GetValueAsync and SetValueAsync Methods</h2><p>In addition to the method for invoking a JS function constructor, we can also access the values of the instance obtained through the methods <code>GetValueAsync&lt;TValue&gt;(string identifier)</code> and <code>SetValueAsync&lt;TValue&gt;(string identifier, TValue value)</code>. A clear example of this can be seen when we obtain the value of the current image and the length for debugging purposes:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token comment">// Step 3</span>
<span class="token keyword">var</span> currentIndex <span class="token operator">=</span> <span class="token keyword">await</span> galleryInstance<span class="token punctuation">.</span><span class="token generic-method function">GetValueAsync<span class="token punctuation">&lt;</span><span class="token keyword">int</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token string">"currentIndex"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Step 4</span>
<span class="token keyword">var</span> imagesLength <span class="token operator">=</span> <span class="token keyword">await</span> galleryInstance<span class="token punctuation">.</span><span class="token generic-method function">GetValueAsync<span class="token punctuation">&lt;</span><span class="token keyword">int</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token string">"images.length"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">//Step 5</span>
currentGalleryInfo <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">GalleryInfo</span>
<span class="token punctuation">{</span>
    CurrentIndex <span class="token operator">=</span> currentIndex<span class="token punctuation">,</span>
    TotalImages <span class="token operator">=</span> imagesLength
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token function">StateHasChanged</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">WriteLine</span><span class="token punctuation">(</span>$<span class="token string">"Modern: Showing {imagesLength} images, starting at index {currentIndex}"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In the above code, these values are displayed through an <code>Console.WriteLine</code>, but you could perfectly use them to modify other UI elements or to perform operations.</p><h2 id="conclusion">Conclusion</h2><p>Throughout this article, you have been introduced to the new JavaScript interop features available in .NET 10, which undoubtedly marks an evolution in the way interaction with JS occurs when necessary. It is time to create safer and typeable code in web apps based on Blazor.</p><hr /><p>Remember, you can try Telerik UI for Blazor free for 30 days:</p><p><a href="https://www.telerik.com/try/ui-for-blazor" target="_blank" class="Btn">Try Now</a></p><img src="https://feeds.telerik.com/link/23050/17309760.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:d682b921-294a-4401-b442-3aed57b43aa9</id>
    <title type="text">What’s New for Blazor in .NET 11 Preview Releases 1 and 2</title>
    <summary type="text">Tour the notable Blazor changes and new features in .NET 11 Previews 1 and 2 for an early glimpse into what’s coming for Blazor in .NET 11.</summary>
    <published>2026-03-25T16:13:51Z</published>
    <updated>2026-06-14T09:54:16Z</updated>
    <author>
      <name>Jon Hilton </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23050/17305972/whats-new-blazor-net-11-preview-releases-1-2"/>
    <content type="text"><![CDATA[<p><span class="featured">Tour the notable Blazor changes and new features in .NET 11 Previews 1 and 2 for an early glimpse into what&rsquo;s coming for Blazor in .NET 11.</span></p><p>Ever since the significant changes that landed with .NET 8, we&rsquo;ve seen incremental updates to Blazor over several releases.</p><p>This year seems set to continue that trend, with some key gaps being filled and refinements to key features. So no structural shifts, new hosting models or render modes, but we do finally get a <code>Label</code> component for forms!</p><p>Here are some notable Blazor changes and new features that landed in .NET 11 Previews 1 and 2.</p><h2 id="tempdata-for-static-ssr">TempData for Static SSR</h2><p>Ever since .NET 8, we&rsquo;ve had SSR mode for Blazor. It&rsquo;s a way of building applications using Blazor&rsquo;s Razor components, but without resorting to Blazor Server or Blazor WASM to run those components.</p><p>With SSR, when a user requests your page, Blazor runs on the server, locates the relevant page component, renders it and returns the generated HTML which is then displayed in the browser.</p><p>In this mode you can also use forms to capture user input.</p><p>But sometimes you want to take information and persist it between page navigations. For example, maybe a user enters their name in a form, and you want to show them a personalized message on the subsequent confirmation screen, &ldquo;Thanks, Jon, for your order.&rdquo;</p><p>Prior to .NET 11, this required you to pass the value along somehow, with common solutions involving query string, session state or custom cookies.</p><p>But MVC and Razor Pages developers have long been able to use something called Temp Data to store that information between screens. Temp Data is specifically for capturing short-lived messages or data that only need to survive one redirect, then disappear.</p><p>In .NET 11, Temp Data is coming to Blazor and will be available as a cascading parameter in static SSR components, with no extra registration needed beyond the usual <code>AddRazorComponents()</code>:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token punctuation">[</span>CascadingParameter<span class="token punctuation">]</span>
<span class="token keyword">public</span> ITempData<span class="token operator">?</span> TempData <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
</code></pre><p>Let&rsquo;s say you&rsquo;re about to redirect your user to a different page. You can write a value to <code>TempData</code>:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">HandleSubmit</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    TempData<span class="token punctuation">[</span><span class="token string">"SuccessMessage"</span><span class="token punctuation">]</span> <span class="token operator">=</span> $<span class="token string">"Thanks {Input.Name}, your message has been sent!"</span><span class="token punctuation">;</span>
    Navigation<span class="token punctuation">.</span><span class="token function">NavigateTo</span><span class="token punctuation">(</span><span class="token string">"/contact/confirmation"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Then pick that up on the page they&rsquo;re redirected to:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token keyword">void</span> <span class="token function">OnInitialized</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token comment">// Get() reads and marks for deletion - one-shot read</span>
    confirmationMessage <span class="token operator">=</span> TempData<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span><span class="token string">"SuccessMessage"</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Under the hood, these values are stored in a cookie in the user&rsquo;s browser.</p><p>Once you&rsquo;ve retrieved a value via <code>Get</code>, it&rsquo;s marked for deletion. So if you want to check the value without it being deleted, you can use <code>Peek</code> instead. If you want to keep something that has been marked for deletion you can call <code>Keep</code> to cancel the deletion.</p><h2 id="ihostedservice-in-blazor-webassembly">IHostedService in Blazor WebAssembly</h2><p>If you&rsquo;re using Blazor WebAssembly, you may well have realized there&rsquo;s one thing you can&rsquo;t easily do with Blazor running in the browser: schedule jobs to run in the background.</p><p>This is a challenge because sometimes you want to separate background work from your component lifecycles. For example, you might want to poll an API (maybe a pricing or notifications endpoint).</p><p>In WASM apps, prior to .NET 11, this has been tricky to achieve, often requiring the use of timers within specific components (tied to component lifecycles and only running when the component is rendered), or singleton services with a manual timer.</p><p>.NET 11 simplifies this with <code>IHostedService</code>.</p><p>You can add a hosted service to your Blazor WASM app and it will start with the app (not a specific component), and run independently of navigation.</p><p><code>AddHostedService&lt;T&gt;()</code> now works with <code>WebAssemblyHostBuilder</code>:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">var</span> builder <span class="token operator">=</span> WebAssemblyHostBuilder<span class="token punctuation">.</span><span class="token function">CreateDefault</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>
builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method function">AddHostedService<span class="token punctuation">&lt;</span>PricePollingService<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">await</span> builder<span class="token punctuation">.</span><span class="token function">Build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">RunAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The service itself is standard <code>BackgroundService</code>, identical to its server-side equivalent:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PricePollingService</span><span class="token punctuation">(</span>PriceState state<span class="token punctuation">)</span> <span class="token punctuation">:</span> BackgroundService
<span class="token punctuation">{</span>
    <span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token keyword">async</span> Task <span class="token function">ExecuteAsync</span><span class="token punctuation">(</span>CancellationToken stoppingToken<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token operator">!</span>stoppingToken<span class="token punctuation">.</span>IsCancellationRequested<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">await</span> <span class="token function">FetchPricesAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            state<span class="token punctuation">.</span><span class="token function">NotifyUpdate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">await</span> Task<span class="token punctuation">.</span><span class="token function">Delay</span><span class="token punctuation">(</span>TimeSpan<span class="token punctuation">.</span><span class="token function">FromSeconds</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span> stoppingToken<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>This example uses a <code>Singleton</code> <code>PriceState</code> service and a component which listens for updates to that state.</p><p>The <code>PriceState</code> service acts as a shared state container which the background service writes to:</p><p><strong>Program.cs</strong></p><pre class=" language-csharp"><code class="prism  language-csharp">builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method function">AddSingleton<span class="token punctuation">&lt;</span>PriceState<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p><strong>PriceState.cs</strong></p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PriceState</span>
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">event</span> Action<span class="token operator">?</span> OnChange<span class="token punctuation">;</span>

    <span class="token keyword">public</span> List<span class="token operator">&lt;</span>PriceQuote<span class="token operator">&gt;</span> Quotes <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token keyword">set</span><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">public</span> DateTimeOffset LastUpdated <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">UpdateQuotes</span><span class="token punctuation">(</span>List<span class="token operator">&lt;</span>PriceQuote<span class="token operator">&gt;</span> quotes<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        Quotes <span class="token operator">=</span> quotes<span class="token punctuation">;</span>
        LastUpdated <span class="token operator">=</span> DateTimeOffset<span class="token punctuation">.</span>UtcNow<span class="token punctuation">;</span>
        OnChange<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">Invoke</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 then you can subscribe to the <code>OnChange</code> event when that data changes:</p><p><strong>PriceWatcher.razor</strong></p><pre class=" language-html"><code class="prism  language-html">@implements IDisposable
@inject PriceState State

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Last updated: @State.LastUpdated<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 comment">&lt;!-- render price data here --&gt;</span>
</code></pre><pre class=" language-csharp"><code class="prism  language-csharp">@code <span class="token punctuation">{</span>
    <span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token keyword">void</span> <span class="token function">OnInitialized</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        State<span class="token punctuation">.</span>OnChange <span class="token operator">+</span><span class="token operator">=</span> HandleStateChanged<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">HandleStateChanged</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token function">InvokeAsync</span><span class="token punctuation">(</span>StateHasChanged<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">Dispose</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        State<span class="token punctuation">.</span>OnChange <span class="token operator">-</span><span class="token operator">=</span> HandleStateChanged<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Important note: WASM is single-threaded. BackgroundService gives you a convenient way to abstract background tasks, but not true parallelism.</p><p>I/O-bound work (polling, fetching) is typically fine because it&rsquo;s mostly waiting (<code>await</code>), which frees the thread up in the meantime. But CPU-heavy work would block the UI.</p><p>But fear not, there&rsquo;s a solution for that too!</p><h2 id="web-worker-template">Web Worker Template</h2><p>For anything CPU-heavy, you want to keep the main thread (which also handles the UI) free.</p><p>.NET 11 introduces <code>dotnet new webworker</code>, which scaffolds a Razor class library with the JS plumbing needed to run .NET code in a browser web worker. Modern web browsers support web workers as a convenient way to run tasks completely separately from your main application&rsquo;s thread.</p><p>The template will create a <code>WebWorkerClient</code> class which uses a factory pattern to create worker instances. Then you can define your worker methods using <code>[JSExport]</code>.</p><p>Here&rsquo;s an example, which computes primes (a CPU-heavy task).</p><p><strong>PrimesWorker.cs</strong></p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token punctuation">[</span><span class="token function">SupportedOSPlatform</span><span class="token punctuation">(</span><span class="token string">"browser"</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">partial</span> <span class="token keyword">class</span> <span class="token class-name">PrimesWorker</span>
<span class="token punctuation">{</span>
    <span class="token punctuation">[</span>JSExport<span class="token punctuation">]</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">string</span> <span class="token function">ComputePrimes</span><span class="token punctuation">(</span><span class="token keyword">int</span> limit<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token comment">// CPU-intensive work runs on the worker thread</span>
        <span class="token comment">// UI stays responsive</span>
        <span class="token keyword">var</span> result <span class="token operator">=</span> <span class="token function">SieveOfEratosthenes</span><span class="token punctuation">(</span>limit<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> JsonSerializer<span class="token punctuation">.</span><span class="token function">Serialize</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">PrimeResult</span><span class="token punctuation">(</span>primes<span class="token punctuation">.</span>Count<span class="token punctuation">,</span> primes<span class="token punctuation">.</span><span class="token function">TakeLast</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ToArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> sw<span class="token punctuation">.</span>ElapsedMilliseconds<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">public</span> record <span class="token function">PrimeResult</span><span class="token punctuation">(</span><span class="token keyword">int</span> Count<span class="token punctuation">,</span> <span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> LastFive<span class="token punctuation">,</span> <span class="token keyword">long</span> ElapsedMs<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>You can invoke this method from a component (via a web worker).</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">private</span> <span class="token keyword">const</span> <span class="token keyword">int</span> limit <span class="token operator">=</span> 50_000_000<span class="token punctuation">;</span>

<span class="token keyword">var</span> worker <span class="token operator">=</span> <span class="token keyword">await</span> WebWorkerClient<span class="token punctuation">.</span><span class="token function">CreateAsync</span><span class="token punctuation">(</span>JSRuntime<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> result <span class="token operator">=</span> <span class="token keyword">await</span> worker<span class="token punctuation">.</span><span class="token generic-method function">InvokeAsync<span class="token punctuation">&lt;</span>PrimeResult<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span>
    <span class="token string">"WebWorkerAppDemo.PrimesWorker.ComputePrimes"</span><span class="token punctuation">,</span>
    args<span class="token punctuation">:</span> <span class="token punctuation">[</span>limit<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>If you were to run that same prime number code directly in a component, it would lock UI updates for as long as it&rsquo;s running. Try it with the above approach (using web workers), and the UI will stay entirely responsive throughout.</p><p>Some important notes about web workers:</p><ul><li>Class must be static partial with <code>[SupportedOSPlatform("browser")]</code>.</li><li>Return types: primitives or strings only (complex types must be serialized to JSON).</li><li>Your project needs <code>&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;</code> set in its <code>csproj</code>.</li><li>The worker loads a second .NET runtime, so startup is slow but compute is genuinely parallel.</li><li>Template produces a class library, which you can then reference from your main project.</li></ul><h2 id="relative-navigation">Relative Navigation</h2><p>This is one of those &ldquo;if you know, you know&rdquo; challenges.</p><p>In previous versions of .NET, when you want to render a relative link, things got tricky. Say you wanted a link to an FAQ page at <code>/faq</code>. .NET would assume you wanted to navigate to <code>/faq</code> at the app root. But if you were already on <code>/docs/</code>, you might well have wanted that link to go to <code>/docs/faq</code>.</p><p>The workaround up to now has been to use hardcoded full paths everywhere, which is asking for trouble when you start moving things around.</p><p><code>NavigationManager.NavigateTo()</code> and <code>NavLink</code> now accept <code>RelativeToCurrentUri</code>, which, when set to <code>true</code>, means relative paths will resolve against the current page path instead of the app root:</p><pre class=" language-html"><code class="prism  language-html">@page "/docs/getting-started"

@* .NET 11 - resolves to /docs/getting-started/overview *@
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>NavLink</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>overview<span class="token punctuation">"</span></span> <span class="token attr-name">RelativeToCurrentUri</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 punctuation">&gt;</span></span>Overview<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>NavLink</span><span class="token punctuation">&gt;</span></span>

@* Before - had to hardcode the full path *@
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>NavLink</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/docs/getting-started/overview<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Overview<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>NavLink</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Programmatic navigation:</p><pre class=" language-csharp"><code class="prism  language-csharp">Navigation<span class="token punctuation">.</span><span class="token function">NavigateTo</span><span class="token punctuation">(</span><span class="token string">"faq"</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">NavigationOptions</span>
<span class="token punctuation">{</span>
    RelativeToCurrentUri <span class="token operator">=</span> <span class="token keyword">true</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Note: Path must not have a leading slash for relative resolution (&ldquo;overview&rdquo; not &ldquo;/overview&rdquo;).</p><h2 id="displayname-and-label-components">DisplayName and Label Components</h2><p>This may well be one of those features that leaves you wondering how it took so long to appear, but Blazor now has a <code>Label</code> component (and a handy <code>DisplayName</code> one too).</p><p>Both components read display names from model attributes:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ProductModel</span>
<span class="token punctuation">{</span>
    <span class="token punctuation">[</span><span class="token function">Display</span><span class="token punctuation">(</span>Name <span class="token operator">=</span> <span class="token string">"Production Date"</span><span class="token punctuation">)</span><span class="token punctuation">]</span>  <span class="token comment">// DisplayName and Label read this</span>
    <span class="token keyword">public</span> DateOnly<span class="token operator">?</span> ProductionDate <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token punctuation">[</span><span class="token function">DisplayName</span><span class="token punctuation">(</span><span class="token string">"Unit Price (&pound;)"</span><span class="token punctuation">)</span><span class="token punctuation">]</span>     <span class="token comment">// Also supported, but [Display] takes precedence</span>
    <span class="token keyword">public</span> <span class="token keyword">decimal</span> Price <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">int</span> StockCount <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>  <span class="token comment">// Falls back to raw property name</span>
<span class="token punctuation">}</span>
</code></pre><p>Here&rsquo;s how you can use them in a form:</p><pre class=" language-html"><code class="prism  language-html">@* Label wraps the input - accessible by default *@
<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>@(() =&gt; Model.ProductionDate)<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>form-label<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>InputDate</span> <span class="token attr-name">@bind-Value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Model.ProductionDate<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>form-control<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>

@* DisplayName standalone *@
<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>DisplayName</span> <span class="token attr-name">For</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@(() =&gt; Model.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>th</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Previously you had to write your own <code>&lt;label&gt;</code> components, so this is a welcome addition.</p><h2 id="environmentboundary-component">EnvironmentBoundary Component</h2><p>Ever felt the need to show different information on the screen depending on which environment your app&rsquo;s running in? (Think UI that only shows up when you&rsquo;re running locally, or on staging.)</p><p>Now you can conditionally render content based on the hosting environment:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>EnvironmentBoundary</span> <span class="token attr-name">Include</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Development<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>Debug tools enabled<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>EnvironmentBoundary</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>EnvironmentBoundary</span> <span class="token attr-name">Exclude</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Production<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>Test banner<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>EnvironmentBoundary</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>EnvironmentBoundary</span> <span class="token attr-name">Include</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Staging,Production<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>Analytics script<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>EnvironmentBoundary</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Previously, you had to inject <code>IWebHostEnvironment</code> and write manual conditional statements. This declarative approach is cleaner (note the matching of environment is case-insensitive).</p><h2 id="basepath-component">BasePath Component</h2><p>Another small but handy change.</p><p><code>&lt;BasePath /&gt;</code> in <code>App.razor</code> replaces the hardcoded <code>&lt;base href="https://www.telerik.com/"&gt;</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>head</span><span class="token punctuation">&gt;</span></span>   
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>BasePath</span> <span class="token punctuation">/&gt;</span></span>   
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>This will take the value from <code>NavigationManager.BaseUri</code> and essentially returns whatever <code>UsePathBase</code> sets (which you can configure in <strong>Program.cs</strong>).</p><p>This is handy if you&rsquo;re running your app on a subpath, as the base href will be automatically set to the correct value.</p><h2 id="signalr-configureconnection">SignalR ConfigureConnection</h2><p>If you need to configure your <code>SignalR</code> connection for Blazor Server, you now have easier config available via <code>AddInteractiveServerRenderMode</code>.</p><p>In .NET 11, it accepts a <code>ConfigureConnection</code> callback for the underlying SignalR connection:</p><pre class=" language-csharp"><code class="prism  language-csharp">app<span class="token punctuation">.</span><span class="token generic-method function">MapRazorComponents<span class="token punctuation">&lt;</span>App<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">AddInteractiveServerRenderMode</span><span class="token punctuation">(</span>options <span class="token operator">=</span><span class="token operator">&gt;</span>
    <span class="token punctuation">{</span>
        options<span class="token punctuation">.</span>ConfigureConnection <span class="token operator">=</span> connectionOptions <span class="token operator">=</span><span class="token operator">&gt;</span>
        <span class="token punctuation">{</span>
            connectionOptions<span class="token punctuation">.</span>ApplicationMaxBufferSize <span class="token operator">=</span> <span class="token number">512</span> <span class="token operator">*</span> <span class="token number">1024</span><span class="token punctuation">;</span>
            connectionOptions<span class="token punctuation">.</span>TransportMaxBufferSize <span class="token operator">=</span> <span class="token number">512</span> <span class="token operator">*</span> <span class="token number">1024</span><span class="token punctuation">;</span>
            connectionOptions<span class="token punctuation">.</span>Transports <span class="token operator">=</span> HttpTransportType<span class="token punctuation">.</span>WebSockets<span class="token punctuation">;</span>
          connectionOptions<span class="token punctuation">.</span>AllowStatefulReconnects <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">;</span>
            connectionOptions<span class="token punctuation">.</span>CloseOnAuthenticationExpiration <span class="token operator">=</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 punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Previously, you had to resort to global SignalR hub config. Now you can target Blazor&rsquo;s hub specifically.</p><p>You&rsquo;ll probably find yourself spending time here if you run into errors because your components hold too much state, you want to tweak stateful reconnection logic or have other reasons to tweak how the SignalR part of Blazor Server works.</p><h2 id="what-to-watch">What to Watch</h2><p>That wraps up a quick tour of some of the highlights of .NET 11 Previews 1 and 2 for Blazor.</p><p>Here are a few things that look set to land in future previews:</p><ul><li><strong>SessionData for static SSR</strong> &ndash; The session-scoped counterpart to TempData</li><li><strong>Cache component</strong> &ndash; Component-level output caching</li><li><strong>Client-side validation without a circuit</strong> &ndash; No need to resort to Blazor Server for your statically rendered forms</li><li><strong>Aspire integration improvements</strong></li><li><strong>Virtualize with variable-height items</strong></li><li><strong><code>[SupplyParameterFromTempData]</code> attribute</strong></li></ul><p>.NET 11 will be released in November, with preview releases dropping every month until then.</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">Build Your Own AI Application Using Prebuilt Blazor Components</h4></div><div class="col-8"><p class="u-fs16 u-mb0">With <a target="_blank" href="https://www.telerik.com/blogs/build-your-own-ai-application-using-prebuilt-blazor-components">prebuilt components, you can easily build a Blazor application</a> that connects to AI model services for chat conversations. Check it out.</p></div></div></aside><img src="https://feeds.telerik.com/link/23050/17305972.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:64742007-b953-46a8-8374-913881b24dee</id>
    <title type="text">Blazor Basics: Implementing a Theme Switch in Blazor (Dark Mode)</title>
    <summary type="text">Learn how to implement dark mode and a theme switch for Blazor web applications using standardized CSS features and no JavaScript code.</summary>
    <published>2026-03-17T20:08:55Z</published>
    <updated>2026-06-14T09:54:16Z</updated>
    <author>
      <name>Claudio Bernasconi </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23050/17301106/blazor-basics-implementing-theme-switch-blazor-dark-mode"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn how to implement dark mode and a theme switch for Blazor web applications using standardized CSS features and no JavaScript code.</span></p><p>In this article, we&rsquo;ll learn how to properly implement dark mode and a theme switch for Blazor web applications.</p><h2 id="introduction">Introduction</h2><p>We want to implement a minimal yet complete example of dark mode and a theme switch for Blazor web applications.</p><p>We will keep it simple and use pure CSS to style the application and Blazor to manage the state. We do not use any JavaScript code for this solution.</p><p><strong>Hint:</strong> Although the code used in the example project is based on the .NET 10 Blazor Web Application project template, which uses Bootstrap for its sample pages, we do not use Bootstrap or any other CSS library to implement the dark mode or the theme switch.</p><p>You can <a target="_blank" href="https://github.com/claudiobernasconi/BlazorDarkMode">access the code used in this example on GitHub</a>.</p><h2 id="the-concept">The Concept</h2><p>There are three core principles we want to follow:</p><ol><li>We define all colors as CSS variables.</li><li>We use a <code>.dark-theme</code> CSS class to override/replace those base colors.</li><li>We implement a Blazor component that toggles this CSS class at runtime.</li></ol><p>This solution works for <strong>Blazor Server</strong> and <strong>Blazor WebAssembly</strong>.</p><h2 id="defining-the-css-color-variables">Defining the CSS Color Variables</h2><p>In the <code>app.css</code> file or any other CSS file referenced in the <code>index.html</code> or <code>App.razor</code> file of your Blazor web application, we add the following CSS variable definitions:</p><pre class=" language-css"><code class="prism  language-css"><span class="token selector"><span class="token pseudo-class">:root</span> </span><span class="token punctuation">{</span>
    <span class="token property">--background-color</span><span class="token punctuation">:</span> <span class="token hexcode">#FFFFFF</span><span class="token punctuation">;</span>
    <span class="token property">--text-color</span><span class="token punctuation">:</span> <span class="token hexcode">#1F1F39</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.dark-theme</span> </span><span class="token punctuation">{</span>
    <span class="token property">--background-color</span><span class="token punctuation">:</span> <span class="token hexcode">#1F1F39</span><span class="token punctuation">;</span>
    <span class="token property">--text-color</span><span class="token punctuation">:</span> <span class="token hexcode">#FAFAFB</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p><strong>Hint:</strong> We keep it simple in this example and use only CSS variables for the background color and text color. In a real-world implementation, you might also want to define CSS variables for border colors, primary and secondary colors, etc.</p><h2 id="applying-the-color-variables">Applying the Color Variables</h2><p>Now that we defined the CSS variables for our desired colors, we need to apply those variables in CSS definitions. Remember that the variable definition above only defines the variables, but does not apply them.</p><pre class=" language-css"><code class="prism  language-css"><span class="token selector"><span class="token class">.theme</span> </span><span class="token punctuation">{</span>
    <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--background-color<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text-color<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Again, we keep it simple and apply the background color and the text color to the theme CSS class. We could go on and define colors for buttons, headings and other parts of the web application.</p><h2 id="adding-the-theme-state-to-the-layout-component">Adding the Theme State to the Layout Component</h2><p>Now that we have the basic building block for styling the component in place, we want to keep track of whether dark mode is in use.</p><p>A simple implementation alters the <code>MainLayout</code> component like this:</p><pre class=" language-html"><code class="prism  language-html">&lt;div class=@($"page theme {ThemeCSSClass}")&gt;
    <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>sidebar<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>NavMenu</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>main</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>top-row px-4<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">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>btn btn-primary<span class="token punctuation">"</span></span> <span class="token attr-name">@onclick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ToggleTheme<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                Toggle Theme
            <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>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>https://learn.microsoft.com/aspnet/core/<span class="token punctuation">"</span></span> <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>_blank<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>About<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</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>article</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>content px-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            @Body
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>article</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>main</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>We add two CSS classes to the class list of the outer <code>div</code> element. In addition to the page CSS class used in the default project template, we also want to add the previously defined <code>theme</code> class, followed by a class name managed by the component.</p><p>We also add a <code>button</code> to toggle the theme.</p><p>We add the following behavior to the code section of the component:</p><pre class=" language-csharp"><code class="prism  language-csharp">@code <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">bool</span> _darkModeEnabled <span class="token operator">=</span> <span class="token keyword">false</span><span class="token punctuation">;</span>

    <span class="token keyword">private</span> <span class="token keyword">string</span> ThemeCSSClass <span class="token operator">=</span><span class="token operator">&gt;</span> _darkModeEnabled <span class="token operator">?</span> <span class="token string">"dark-theme"</span> <span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">;</span>

    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">ToggleTheme</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        _darkModeEnabled <span class="token operator">=</span> <span class="token operator">!</span>_darkModeEnabled<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>The code defines a <code>_darkModeEnabled</code> variable that tracks the user&rsquo;s theme choice. We conditionally return <code>dark-theme</code> or an empty string for the <code>ThemeCSSClass</code> property, which is then rendered as part of the CSS class name list for the Layout component&rsquo;s outer <code>div</code>.</p><p>The <code>ToggleTheme</code> method is triggered when the user presses the <code>button</code> and wants to switch the theme. It flips the value of the <code>_darkModeEnabled</code> boolean variable.</p><h2 id="theming-in-action">Theming in Action</h2><p>The user can now toggle the light and dark themes using the button in the page header.</p><p><img title="Blazor web Application using light mode" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/blazor-light-mode.png?sfvrsn=d20bcc54_2" alt="A browser with a Blazor web application using a light mode theme with a dark text color and a white background." /></p><p><img title="Blazor web Application using light mode" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/blazor-dark-mode.png?sfvrsn=9b1faed_2" alt="A browser with a Blazor web application using a dark mode theme with a light text color and a dark background." /></p><h2 id="why-this-solution-works-well-in-blazor">Why This Solution Works Well in Blazor</h2><p>This solution leverages how Razor component rendering works. Whenever the state of a component changes, the component is re-rendered.</p><p>For the layout component, this means that whenever the user presses the button, the component&rsquo;s state changes, so it will be re-rendered. As part of the rendering process, the correct CSS classes will be applied.</p><p>A declarative user interface definition combined with state-driven component rendering is the strength of Blazor, and our solution therefore fits it perfectly.</p><h2 id="improving-the-user-experience">Improving the User Experience</h2><p>There are two main areas that could be improved to take our simple solution to the next level:</p><ul><li>The theme state is currently attached to the <code>MainLayout</code> component. It means that if the user closes the browser tab or refreshes the page, the state is lost. Persisting the theme choice using local storage is a great idea to keep the user experience consistent. Learn more about <a target="_blank" href="https://www.telerik.com/blogs/blazor-basics-accessing-browser-storage-blazor-web-applications">accessing the local storage for Blazor Server web applications</a> or how to use <a target="_blank" href="https://www.telerik.com/blogs/blazor-basics-webassembly-using-local-storage-offline-scenarios">local Storage in Blazor WebAssembly applications</a>.</li><li>You could respect the system preferences and apply them when a particular user starts the web application for the first time. CSS provides the <code>preferes-color-scheme</code> media feature. The code would look like this:</li></ul><pre class=" language-css"><code class="prism  language-css"><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">prefers-color-scheme</span><span class="token punctuation">:</span> dark<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token selector"><span class="token pseudo-class">:root</span> </span><span class="token punctuation">{</span>
        <span class="token comment">/* variable definitions */</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">prefers-color-scheme</span><span class="token punctuation">:</span> light<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token selector"><span class="token pseudo-class">:root</span> </span><span class="token punctuation">{</span>
        <span class="token comment">/* variable definitions */</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><h2 id="the-limitations-of-this-approach">The Limitations of This Approach</h2><p>As shown in the previous chapter on improving the user experience of our simple solutions, our approach is basic and doesn&rsquo;t scale well. The following imminent limitations come to mind:</p><ul><li>Handling <strong>system preferences</strong> already adds complexity to our solution and requires more code to cleanly implement the expected behavior.</li><li>CSS variables and definitions only <strong>cascade down the DOM tree</strong>. In our example, we add the themed CSS classes to the MainLayout component. Components rendered outside the <code>MainLayout</code> component element tree are out of scope for theming and must be treated the same way (by adding the <code>theme</code> and <code>dark-mode</code> CSS classes).</li><li>Changing colors and adjusting the theme requires altering <strong>global CSS definitions</strong>, which is hard to test and can potentially have unexpected side effects. Also, making sure to apply the CSS variables in the correct applicable CSS classes doesn&rsquo;t scale.</li><li><strong>Third-party components</strong> will not automatically apply the custom CSS classes defined in the application. Meaning that if you integrate third-party components, you will need to implement additional code to integrate them with your custom theming implementation.</li><li>Implementing <strong>multiple themes</strong> becomes even harder to maintain. Working with light and dark mode should not add too much complexity, but maintaining three or four, or even 10 different themes becomes much harder.</li><li>You have to verify the selected colors work together and <strong>meet accessibility requirements</strong> (e.g., color contrast). And let&rsquo;s be honest&mdash;not all developers are good designers.</li></ul><p>For a small website, the approach shown in this article will probably work well. For larger web applications consisting of hundreds of pages and components, it can become a maintenance nightmare if the implementation is not carefully architected to properly handle state changes and apply the correct CSS classes for each component during rendering.</p><h2 id="how-telerik-ui-for-blazor-solves-theming-at-scale">How Telerik UI for Blazor Solves Theming at Scale</h2><p>In modern large-scale web applications, theming is important and helps meet accessibility requirements and expected user experience standards.</p><p>The Progress Telerik UI for <a target="_blank" href="https://www.telerik.com/blazor-ui">Blazor component library</a> provides a <a target="_blank" href="https://www.telerik.com/blazor-ui/documentation/styling-and-themes/themebuilder">Blazor ThemeBuilder</a> tool that allows visual customization (color previews), SCSS-based design tokens and built-in dark and light themes.</p><p>And most importantly, the themes are applied consistently across all components.</p><p>It is still important to understand how theming works under the hood, but for a professional web application, using a professionally implemented theming system can prevent headaches and reduce the amount of custom code required. Plus, accessibility features are baked in.</p><p>Learn more about theming from <a target="_blank" href="https://www.telerik.com/blogs/author/peter-vogel">Peter Vogel</a> in the <a target="_blank" href="https://www.telerik.com/blogs/themes-magic-telerik-ui-blazor">Themes Magic in Telerik UI for Blazor</a> article.</p><h2 id="conclusion">Conclusion</h2><p>We learned how to implement a simple solution for a theme switch and light and dark mode in a Blazor web application. This basic solution works for Blazor Server and Blazor WebAssembly because it uses standardized CSS features and no JavaScript.</p><p>We learned how to further improve the solution and what limitations it will face for a large-scale web application.</p><p>Professionally implemented user interface component libraries, such as <a target="_blank" href="https://www.telerik.com/blazor-ui">Telerik UI for Blazor</a>, implement complex theming systems that we can leverage to get around those limitations.</p><hr /><p>If you want to learn more about Blazor development, watch my <a target="_blank" href="https://www.youtube.com/playlist?list=PLwISgxnkpZGL_LhTQCWwp-WCzupv7lcp0">free Blazor Crash Course</a> on YouTube. And stay tuned to the Telerik blog for more <a target="_blank" href="https://www.telerik.com/blogs/tag/blazor-basics">Blazor Basics</a>.</p><img src="https://feeds.telerik.com/link/23050/17301106.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:9ed4819f-b7ee-4208-b031-ba0e298fab0b</id>
    <title type="text">Customizing the New ReconnectModal Component in Blazor 10</title>
    <summary type="text">Learn how to customize the reconnection modal dialog for users of your Blazor app with the ReconnectionModal component, introduced in .NET 10.</summary>
    <published>2026-03-03T16:17:41Z</published>
    <updated>2026-06-14T09:54:16Z</updated>
    <author>
      <name>Héctor Pérez </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23050/17288838/customizing-new-reconnectmodal-component-blazor-10"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn how to customize the reconnection modal dialog for users of your Blazor app with the ReconnectionModal component, introduced in .NET 10.</span></p><p>.NET 10 has arrived with a lot of new features for its main development technologies. Blazor is no exception, and several features have been added that make the platform increasingly robust and customizable year after year for creating web applications.</p><p>One of these features is the addition of a customizable reconnection modal dialog, which we will discuss in depth in this article.</p><h2 id="understanding-the-new-reconnectionmodal-component-of-blazor">Understanding the New ReconnectionModal Component of Blazor</h2><p>Before .NET 10, when there were disconnection events in a Blazor application, a modal was displayed with information to the user about the reconnection status. However, the modal was not very easy to customize and caused <strong>Content Security Policy</strong> issues and injected styles.</p><p>This completely changes in .NET 10, with the incorporation of a component called <strong>ReconnectModal</strong>, consisting of a Razor file for layout, a styles file to define the design and a JS code file to utilize the logic. Among these three files, you can customize the reconnection component as much as you want, as we will see next.</p><p>A new event <code>components-reconnect-state-changed</code> has also been added to detect reconnection status changes, as well as a new reconnection status called <code>retrying</code>, which you can use to show a different design after a first reconnection attempt.</p><h2 id="general-structure-of-the-reconnectionmodal-component">General Structure of the ReconnectionModal Component</h2><p>The file <code>ReconnectModal.razor</code> contains the layout for the reconnection dialog component. The first line with a tag <code>script</code> loads the file <code>ReconnectModal.razor.js</code> that enables interactivity in the component. This file <code>js</code> can be left as is, as the logic in the file covers everything necessary for managing the reconnection dialog, including interaction buttons:</p><pre class=" language-javascript"><code class="prism  language-javascript"><span class="token operator">&lt;</span>script type<span class="token operator">=</span><span class="token string">"module"</span> src<span class="token operator">=</span><span class="token string">"@Assets["</span>Components<span class="token operator">/</span>Layout<span class="token operator">/</span>ReconnectModal<span class="token punctuation">.</span>razor<span class="token punctuation">.</span>js<span class="token string">"]"</span><span class="token operator">&gt;</span><span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">&gt;</span>
</code></pre><p>In the previous tag, the expression <code>@Assets</code> allows resolving the path of a static resource that will be used in the component, commonly with the same name as the component.</p><p>Next, we find an element <code>dialog</code> that is used to show reconnection information to the user. In this element, we must leave the <code>id</code> <code>components-reconnect-modal</code>, as it will be used internally by the framework to display the reconnection message to the user.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dialog</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>components-reconnect-modal<span class="token punctuation">"</span></span> <span class="token attr-name">data-nosnippet</span><span class="token punctuation">&gt;</span></span>
    ...
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dialog</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Within the dialog tag, we define the layout that we can modify as much as we want, as long as we limit ourselves to using code <code>HTML</code> + <code>CSS</code> + <code>JS</code>, due to the fact that this dialog must be displayed when the circuit is down.</p><p>Additionally, you should take care to reuse the <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/signalr?view=aspnetcore-10.0#reflect-the-server-side-connection-state-in-the-ui">classes and ids used in Blazor reconnection tracking</a>, which are defined in the <code>css</code> file:</p><ul><li><code>components-reconnect-show</code></li><li><code>components-reconnect-hide</code></li><li><code>components-reconnect-retrying</code></li><li><code>components-reconnect-failed</code></li><li><code>components-reconnect-rejected</code></li></ul><p>The previous classes are set or unset directly by Blazor when different connection status changes occur. Furthermore, in the <code>ReconnectModal.razor.js</code> file, the event <code>components-reconnect-state-changed</code> is used, which indicates when there is a change in reconnection status, carrying out the display, hiding, reloading or necessary processing according to that status:</p><pre class=" language-javascript"><code class="prism  language-javascript"><span class="token comment">// Set up event handlers</span>
<span class="token keyword">const</span> reconnectModal <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"components-reconnect-modal"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
reconnectModal<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"components-reconnect-state-changed"</span><span class="token punctuation">,</span> handleReconnectStateChanged<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token operator">...</span>

<span class="token keyword">function</span> <span class="token function">handleReconnectStateChanged</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span>detail<span class="token punctuation">.</span>state <span class="token operator">===</span> <span class="token string">"show"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        reconnectModal<span class="token punctuation">.</span><span class="token function">showModal</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">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span>detail<span class="token punctuation">.</span>state <span class="token operator">===</span> <span class="token string">"hide"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        reconnectModal<span class="token punctuation">.</span><span class="token function">close</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">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span>detail<span class="token punctuation">.</span>state <span class="token operator">===</span> <span class="token string">"failed"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"visibilitychange"</span><span class="token punctuation">,</span> retryWhenDocumentBecomesVisible<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span>detail<span class="token punctuation">.</span>state <span class="token operator">===</span> <span class="token string">"rejected"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        location<span class="token punctuation">.</span><span class="token function">reload</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 operator">...</span>
</code></pre><p>Returning to <code>ReconnectModal.razor</code>, the <code>div</code> with the class <code>components-reconnect-container</code> serves to define the graphical appearance of the container, and you can modify it or even remove it if you do not need it.</p><p>The same can be done with the classes defined in <code>ReconnectModal.razor.css</code>, such as <code>components-reconnect-first-attempt-visible</code>, <code>components-reconnect-repeated-attempt-visible</code>, etc., although to make the most of the code you can reuse them if you wish.</p><h2 id="modifying-the-loader-of-the-reconnectmodal-component">Modifying the Loader of the ReconnectModal Component</h2><p>In the file <code>ReconnectModal.razor</code>, we can see an <code>div</code> with the class <code>components-rejoining-animation</code>, which allows showing an animation to the user. If you want to modify it, you can use some premade animation from websites like <a target="_blank" href="https://loading.io/css/">Pure CSS Loaders</a>, or you can write your own CSS animations as we will do next.</p><p>For my example, in <code>ReconnectModal.razor</code>, I will change the tag with the class <code>components-rejoining-animation</code> along with its content to this:</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">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>reconnect-progress components-reconnect-first-attempt-visible<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>progress-bar<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 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>reconnect-progress components-reconnect-repeated-attempt-visible<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>progress-bar<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 tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Next, in <code>ReconnectModal.razor.css</code>, I replace the selector <code>.components-rejoining-animation</code> along with its descendant and structural selectors with this:</p><pre class=" language-css"><code class="prism  language-css"><span class="token selector"><span class="token class">.reconnect-progress</span> </span><span class="token punctuation">{</span>
    <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span>
    <span class="token property">bottom</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token property">left</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <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">height</span><span class="token punctuation">:</span> <span class="token number">4</span>px<span class="token punctuation">;</span>
    <span class="token property">background</span><span class="token punctuation">:</span> <span class="token hexcode">#e2e8f0</span><span class="token punctuation">;</span>
    <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.progress-bar</span> </span><span class="token punctuation">{</span>
    <span class="token property">height</span><span class="token punctuation">:</span> <span class="token number">100%</span><span class="token punctuation">;</span>
    <span class="token property">width</span><span class="token punctuation">:</span> <span class="token number">30%</span><span class="token punctuation">;</span>
    <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">linear-gradient</span><span class="token punctuation">(</span><span class="token number">90</span>deg, <span class="token hexcode">#3b82f6</span> <span class="token number">0%</span>, <span class="token hexcode">#8b5cf6</span> <span class="token number">50%</span>, <span class="token hexcode">#3b82f6</span> <span class="token number">100%</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">background-size</span><span class="token punctuation">:</span> <span class="token number">200%</span> <span class="token number">100%</span><span class="token punctuation">;</span>
    <span class="token property">animation</span><span class="token punctuation">:</span> progressMove <span class="token number">1.5</span>s ease-in-out infinite<span class="token punctuation">;</span>
    <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token number">2</span>px<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@keyframes</span> progressMove</span> <span class="token punctuation">{</span>
    <span class="token selector">0% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span>-<span class="token number">100%</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">background-position</span><span class="token punctuation">:</span> <span class="token number">0%</span> <span class="token number">50%</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector">50% </span><span class="token punctuation">{</span>
        <span class="token property">background-position</span><span class="token punctuation">:</span> <span class="token number">100%</span> <span class="token number">50%</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector">100% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span><span class="token number">400%</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">background-position</span><span class="token punctuation">:</span> <span class="token number">0%</span> <span class="token number">50%</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>These few lines of code completely change the appearance of the loader to a more modern and professional style:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/enhancing-the-loading-animation-of-the-reconnectmodal-razor-component.gif?sfvrsn=a6c98305_2" alt="Enhancing the loading animation of the ReconnectModal.razor component" /></p><p>Now, let&rsquo;s see how to change the modal container.</p><h2 id="modifying-the-modal-container">Modifying the Modal Container</h2><p>In the previous section, you saw that the modal&rsquo;s previous size has become smaller because we removed space from the animation. To solve this, we can modify the modal properties through the class <code>components-reconnect-container</code>. To achieve this, we will go to the CSS file and modify the selector&rsquo;s content as follows:</p><pre class=" language-css"><code class="prism  language-css"><span class="token selector"><span class="token class">.components-reconnect-container</span> </span><span class="token punctuation">{</span>
    <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token number">2.5</span>rem <span class="token number">2</span>rem <span class="token number">2</span>rem<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">flex-direction</span><span class="token punctuation">:</span> column<span class="token punctuation">;</span>
    <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
    <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token number">1.5</span>rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>This way, when viewing the dialog, we will see more space. You can modify the class as much as you want to meet your needs:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/expanding-the-dialog-space-for-better-visibility.png?sfvrsn=9820ee59_2" alt="Expanding the dialog space for better visibility" /></p><p>Let&rsquo;s continue improving the dialog by styling more visual elements.</p><h2 id="adding-a-pulse-element">Adding a Pulse Element</h2><p>To make the dialog take better shape, we can add a set of <code>div</code> and <code>svg</code> tags to show different content according to the reconnection status. We can do this within the <code>div</code> with the class <code>components-reconnect-container</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">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>components-reconnect-container<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>reconnect-icon-container<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>reconnect-pulse-ring<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 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>reconnect-pulse-ring delay-1<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 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>reconnect-pulse-ring delay-2<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 tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>reconnect-icon<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0 0 24 24<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>none<span class="token punctuation">"</span></span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<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>path</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>icon-path<span class="token punctuation">"</span></span> <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>currentColor<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>svg</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>reconnect-icon-error<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0 0 24 24<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>none<span class="token punctuation">"</span></span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<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>path</span> <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>currentColor<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>svg</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>reconnect-icon-pause<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0 0 24 24<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>none<span class="token punctuation">"</span></span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<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>path</span> <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 14H9V8h2v8zm4 0h-2V8h2v8z<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>currentColor<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>svg</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>In the <code>css</code> file, we must control when each element will appear by reusing the selectors for the connection states, as shown below:</p><pre class=" language-css"><code class="prism  language-css"><span class="token comment">/* Icon container */</span>
<span class="token selector"><span class="token class">.reconnect-icon-container</span> </span><span class="token punctuation">{</span>
    <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span>
    <span class="token property">width</span><span class="token punctuation">:</span> <span class="token number">100</span>px<span class="token punctuation">;</span>
    <span class="token property">height</span><span class="token punctuation">:</span> <span class="token number">100</span>px<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">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
    <span class="token property">justify-content</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.reconnect-icon</span>,
<span class="token class">.reconnect-icon-error</span>,
<span class="token class">.reconnect-icon-pause</span> </span><span class="token punctuation">{</span>
    <span class="token property">width</span><span class="token punctuation">:</span> <span class="token number">48</span>px<span class="token punctuation">;</span>
    <span class="token property">height</span><span class="token punctuation">:</span> <span class="token number">48</span>px<span class="token punctuation">;</span>
    <span class="token property">color</span><span class="token punctuation">:</span> <span class="token hexcode">#3b82f6</span><span class="token punctuation">;</span>
    <span class="token property">z-index</span><span class="token punctuation">:</span> <span class="token number">10</span><span class="token punctuation">;</span>
    <span class="token property">animation</span><span class="token punctuation">:</span> iconPulse <span class="token number">2</span>s ease-in-out infinite<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.reconnect-icon-error</span>,
<span class="token class">.reconnect-icon-pause</span> </span><span class="token punctuation">{</span>
    <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token id">#components-reconnect-modal</span><span class="token class">.components-reconnect-failed</span> <span class="token class">.reconnect-icon</span>,
<span class="token id">#components-reconnect-modal</span><span class="token class">.components-reconnect-resume-failed</span> <span class="token class">.reconnect-icon</span> </span><span class="token punctuation">{</span>
    <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token id">#components-reconnect-modal</span><span class="token class">.components-reconnect-failed</span> <span class="token class">.reconnect-icon-error</span>,
<span class="token id">#components-reconnect-modal</span><span class="token class">.components-reconnect-resume-failed</span> <span class="token class">.reconnect-icon-error</span> </span><span class="token punctuation">{</span>
    <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span>
    <span class="token property">color</span><span class="token punctuation">:</span> <span class="token hexcode">#ef4444</span><span class="token punctuation">;</span>
    <span class="token property">animation</span><span class="token punctuation">:</span> iconShake <span class="token number">0.5</span>s ease-in-out<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token id">#components-reconnect-modal</span><span class="token class">.components-reconnect-paused</span> <span class="token class">.reconnect-icon</span> </span><span class="token punctuation">{</span>
    <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token id">#components-reconnect-modal</span><span class="token class">.components-reconnect-paused</span> <span class="token class">.reconnect-icon-pause</span> </span><span class="token punctuation">{</span>
    <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span>
    <span class="token property">color</span><span class="token punctuation">:</span> <span class="token hexcode">#f59e0b</span><span class="token punctuation">;</span>
    <span class="token property">animation</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@keyframes</span> iconPulse</span> <span class="token punctuation">{</span>
    <span class="token selector">0%, 100% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</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 selector">50% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span><span class="token number">1.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 atrule"><span class="token rule">@keyframes</span> iconShake</span> <span class="token punctuation">{</span>
    <span class="token selector">0%, 100% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><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 selector">20% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span>-<span class="token number">8</span>px<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector">40% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span><span class="token number">8</span>px<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector">60% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</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 punctuation">}</span>

    <span class="token selector">80% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</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 punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Pulse rings */</span>
<span class="token selector"><span class="token class">.reconnect-pulse-ring</span> </span><span class="token punctuation">{</span>
    <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span>
    <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">height</span><span class="token punctuation">:</span> <span class="token number">100%</span><span class="token punctuation">;</span>
    <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token number">50%</span><span class="token punctuation">;</span>
    <span class="token property">border</span><span class="token punctuation">:</span> <span class="token number">3</span>px solid <span class="token hexcode">#3b82f6</span><span class="token punctuation">;</span>
    <span class="token property">opacity</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token property">animation</span><span class="token punctuation">:</span> pulseRing <span class="token number">2</span>s <span class="token function">cubic-bezier</span><span class="token punctuation">(</span><span class="token number">0</span>, <span class="token number">0.5</span>, <span class="token number">0.5</span>, <span class="token number">1</span><span class="token punctuation">)</span> infinite<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.reconnect-pulse-ring.delay-1</span> </span><span class="token punctuation">{</span>
        <span class="token property">animation-delay</span><span class="token punctuation">:</span> <span class="token number">0.4</span>s<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.reconnect-pulse-ring.delay-2</span> </span><span class="token punctuation">{</span>
        <span class="token property">animation-delay</span><span class="token punctuation">:</span> <span class="token number">0.8</span>s<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

<span class="token selector"><span class="token id">#components-reconnect-modal</span><span class="token class">.components-reconnect-failed</span> <span class="token class">.reconnect-pulse-ring</span>,
<span class="token id">#components-reconnect-modal</span><span class="token class">.components-reconnect-resume-failed</span> <span class="token class">.reconnect-pulse-ring</span>,
<span class="token id">#components-reconnect-modal</span><span class="token class">.components-reconnect-paused</span> <span class="token class">.reconnect-pulse-ring</span> </span><span class="token punctuation">{</span>
    <span class="token property">animation</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
    <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@keyframes</span> pulseRing</span> <span class="token punctuation">{</span>
    <span class="token selector">0% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span><span class="token number">0.5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">opacity</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector">20% </span><span class="token punctuation">{</span>
        <span class="token property">opacity</span><span class="token punctuation">:</span> <span class="token number">0.8</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector">100% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span><span class="token number">1.2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">opacity</span><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>
</code></pre><p>The above code allows for a pulse effect that, along with the changes we will make later, will look phenomenal:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/adding-a-visual-pulse-effect-to-the-dialog.gif?sfvrsn=3a31b899_2" alt="Adding a visual pulse effect to the dialog" /></p><p>Now, let&rsquo;s see how to modify the content of the reconnection modal.</p><h2 id="modifying-the-reconnection-modal-content">Modifying the Reconnection Modal Content</h2><p>As I mentioned earlier, something that is recommended when modifying the <code>ReconnectModal</code> component is to reuse the template classes.</p><p>One way to do this is to use them on existing elements or by creating new tags and assigning them classes like <code>components-reconnect-first-attempt-visible</code>, <code>components-reconnect-repeated-attempt-visible</code>, etc. Here you can take the opportunity to add additional classes that you can style and animate according to your site&rsquo;s or brand&rsquo;s design:</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">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>reconnect-content<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>h2</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>reconnect-title components-reconnect-first-attempt-visible<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        Reconnecting...
    <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 attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>reconnect-subtitle components-reconnect-first-attempt-visible<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        Restoring connection to the server
    <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>h2</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>reconnect-title components-reconnect-repeated-attempt-visible<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        Retrying connection
    <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 attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>reconnect-subtitle components-reconnect-repeated-attempt-visible<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        Next attempt in <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>components-seconds-to-next-attempt<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>countdown-badge<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>span</span><span class="token punctuation">&gt;</span></span> seconds
    <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>h2</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>reconnect-title error components-reconnect-failed-visible<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        Connection lost
    <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 attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>reconnect-subtitle components-reconnect-failed-visible<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        Could not restore connection to the server
    <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>h2</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>reconnect-title warning components-pause-visible<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        Session paused
    <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 attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>reconnect-subtitle components-pause-visible<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        The server has temporarily paused the session
    <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>h2</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>reconnect-title error components-resume-failed-visible<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        Resume failed
    <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 attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>reconnect-subtitle components-resume-failed-visible<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        Could not resume the session. Please reload the page.
    <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 punctuation">&gt;</span></span>
</code></pre><p>In the previous code, we follow the same logic of the template to show different messages according to the connection status. Additionally, we can also take advantage of separating the buttons into a new section, as in the following example:</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">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>reconnect-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">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>components-reconnect-button<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>btn-primary components-reconnect-failed-visible<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>svg</span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0 0 24 24<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>18<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>18<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>currentColor<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>path</span> <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z<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>svg</span><span class="token punctuation">&gt;</span></span>
        Retry
    <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">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>components-resume-button<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>btn-primary components-pause-visible<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>svg</span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0 0 24 24<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>18<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>18<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>currentColor<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>path</span> <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>M8 5v14l11-7z<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>svg</span><span class="token punctuation">&gt;</span></span>
        Resume
    <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>
</code></pre><p>Finally, we can modify and add styles to enhance the visual appearance:</p><pre class=" language-css"><code class="prism  language-css"><span class="token selector"><span class="token class">...</span>
<span class="token id">#components-reconnect-modal</span> </span><span class="token punctuation">{</span>
    <span class="token selector">background: linear-gradient(145deg, <span class="token id">#1e293b</span> 0%, <span class="token id">#0f172a</span> 100%);
    width: 20rem;
    margin: 20vh auto;
    padding: 2rem;
    border: 0;
    border-radius: 0<span class="token class">.5rem</span>;
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0<span class="token class">.5</span>), 0 0 0 1px rgba(255, 255, 255, 0<span class="token class">.1</span>);
    opacity: 0;
    transition: display 0<span class="token class">.5s</span> allow-discrete, overlay 0<span class="token class">.5s</span> allow-discrete;
    animation: components-reconnect-modal-fadeOutOpacity 0<span class="token class">.5s</span> both;

    &amp;<span class="token attribute">[open]</span> </span><span class="token punctuation">{</span>
        <span class="token property">animation</span><span class="token punctuation">:</span> components-reconnect-modal-slideUp <span class="token number">1.5</span>s <span class="token function">cubic-bezier</span><span class="token punctuation">(</span><span class="token number">.05</span>, <span class="token number">.89</span>, <span class="token number">.25</span>, <span class="token number">1.02</span><span class="token punctuation">)</span> <span class="token number">0.3</span>s, components-reconnect-modal-fadeInOpacity <span class="token number">0.5</span>s ease-in-out <span class="token number">0.3</span>s<span class="token punctuation">;</span>
        <span class="token property">animation-fill-mode</span><span class="token punctuation">:</span> both<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token number">...</span>
<span class="token comment">/* Content */</span>
<span class="token selector"><span class="token class">.reconnect-content</span> </span><span class="token punctuation">{</span>
    <span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Titles */</span>
<span class="token selector"><span class="token class">.reconnect-title</span> </span><span class="token punctuation">{</span>
    <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token number">0</span> <span class="token number">0</span> <span class="token number">0.5</span>rem<span class="token punctuation">;</span>
    <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token number">1.5</span>rem<span class="token punctuation">;</span>
    <span class="token property">font-weight</span><span class="token punctuation">:</span> <span class="token number">700</span><span class="token punctuation">;</span>
    <span class="token property">color</span><span class="token punctuation">:</span> <span class="token hexcode">#f1f5f9</span><span class="token punctuation">;</span>
    <span class="token property">letter-spacing</span><span class="token punctuation">:</span> -<span class="token number">0.02</span>em<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.reconnect-title.error</span> </span><span class="token punctuation">{</span>
        <span class="token property">color</span><span class="token punctuation">:</span> <span class="token hexcode">#f87171</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.reconnect-title.warning</span> </span><span class="token punctuation">{</span>
        <span class="token property">color</span><span class="token punctuation">:</span> <span class="token hexcode">#fbbf24</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.reconnect-subtitle</span> </span><span class="token punctuation">{</span>
    <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token number">0.95</span>rem<span class="token punctuation">;</span>
    <span class="token property">color</span><span class="token punctuation">:</span> <span class="token hexcode">#94a3b8</span><span class="token punctuation">;</span>
    <span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token number">1.5</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Progress */</span>
<span class="token selector"><span class="token class">.reconnect-progress</span> </span><span class="token punctuation">{</span>
    <span class="token property">background</span><span class="token punctuation">:</span> <span class="token hexcode">#334155</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Badge */</span>
<span class="token selector"><span class="token class">.countdown-badge</span> </span><span class="token punctuation">{</span>
    <span class="token property">display</span><span class="token punctuation">:</span> inline-flex<span class="token punctuation">;</span>
    <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
    <span class="token property">justify-content</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
    <span class="token property">min-width</span><span class="token punctuation">:</span> <span class="token number">28</span>px<span class="token punctuation">;</span>
    <span class="token property">height</span><span class="token punctuation">:</span> <span class="token number">28</span>px<span class="token punctuation">;</span>
    <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token number">0</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 function">linear-gradient</span><span class="token punctuation">(</span><span class="token number">135</span>deg, <span class="token hexcode">#3b82f6</span> <span class="token number">0%</span>, <span class="token hexcode">#2563eb</span> <span class="token number">100%</span><span class="token punctuation">)</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 property">font-weight</span><span class="token punctuation">:</span> <span class="token number">700</span><span class="token punctuation">;</span>
    <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token number">0.875</span>rem<span class="token punctuation">;</span>
    <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token number">14</span>px<span class="token punctuation">;</span>
    <span class="token property">box-shadow</span><span class="token punctuation">:</span> <span class="token number">0</span> <span class="token number">2</span>px <span class="token number">8</span>px <span class="token function">rgba</span><span class="token punctuation">(</span><span class="token number">0</span>, <span class="token number">0</span>, <span class="token number">0</span>, <span class="token number">0.6</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Actions */</span>
<span class="token selector"><span class="token class">.reconnect-actions</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">0.75</span>rem<span class="token punctuation">;</span>
    <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 punctuation">}</span>

<span class="token selector"><span class="token class">.btn-primary</span> </span><span class="token punctuation">{</span>
    <span class="token property">flex</span><span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
    <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
    <span class="token property">justify-content</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
    <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token number">0.5</span>rem<span class="token punctuation">;</span>
    <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token number">0.875</span>rem <span class="token number">1.5</span>rem<span class="token punctuation">;</span>
    <span class="token property">border</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
    <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token number">12</span>px<span class="token punctuation">;</span>
    <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token number">1</span>rem<span class="token punctuation">;</span>
    <span class="token property">font-weight</span><span class="token punctuation">:</span> <span class="token number">600</span><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 property">transition</span><span class="token punctuation">:</span> all <span class="token number">0.2</span>s ease<span class="token punctuation">;</span>
    <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">linear-gradient</span><span class="token punctuation">(</span><span class="token number">135</span>deg, <span class="token hexcode">#3b82f6</span> <span class="token number">0%</span>, <span class="token hexcode">#2563eb</span> <span class="token number">100%</span><span class="token punctuation">)</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 property">box-shadow</span><span class="token punctuation">:</span> <span class="token number">0</span> <span class="token number">4</span>px <span class="token number">14</span>px <span class="token function">rgba</span><span class="token punctuation">(</span><span class="token number">59</span>, <span class="token number">130</span>, <span class="token number">246</span>, <span class="token number">0.4</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token id">#components-reconnect-modal</span><span class="token class">.components-reconnect-failed</span> <span class="token class">.btn-primary.components-reconnect-failed-visible</span>,
<span class="token id">#components-reconnect-modal</span><span class="token class">.components-reconnect-paused</span> <span class="token class">.btn-primary.components-pause-visible</span> </span><span class="token punctuation">{</span>
    <span class="token property">display</span><span class="token punctuation">:</span> inline-flex<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.btn-primary</span><span class="token pseudo-class">:hover</span> </span><span class="token punctuation">{</span>
    <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateY</span><span class="token punctuation">(</span>-<span class="token number">2</span>px<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">box-shadow</span><span class="token punctuation">:</span> <span class="token number">0</span> <span class="token number">6</span>px <span class="token number">20</span>px <span class="token function">rgba</span><span class="token punctuation">(</span><span class="token number">59</span>, <span class="token number">130</span>, <span class="token number">246</span>, <span class="token number">0.5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">linear-gradient</span><span class="token punctuation">(</span><span class="token number">135</span>deg, <span class="token hexcode">#2563eb</span> <span class="token number">0%</span>, <span class="token hexcode">#1d4ed8</span> <span class="token number">100%</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.btn-primary</span><span class="token pseudo-class">:active</span> </span><span class="token punctuation">{</span>
    <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateY</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">box-shadow</span><span class="token punctuation">:</span> <span class="token number">0</span> <span class="token number">2</span>px <span class="token number">8</span>px <span class="token function">rgba</span><span class="token punctuation">(</span><span class="token number">59</span>, <span class="token number">130</span>, <span class="token number">246</span>, <span class="token number">0.4</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>With the applied changes, we will have a new and improved dialog that shows the different connection states. In the following image, you can see the dialog when a connection is retried for the first time:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/improved-reconnection-component-adapted-to-a-modern-ui.gif?sfvrsn=1448dc3c_2" alt="Improved reconnection component, adapted to a modern UI" /></p><p>Next, I will show you the rendered dialog when subsequent connection retries are made after the first one:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/reconnection-dialog-showing-subsequent-reconnection-attempts-after-the-initial-failure.png?sfvrsn=2e007dc_2" alt="Reconnection dialog showing subsequent reconnection attempts after the initial failure" /></p><p>Finally, after the connection attempts have failed, you can see the dialog displaying buttons according to the actions the user can take, such as trying to reconnect the application again:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/dialog-displaying-action-buttons-after-all-reconnection-attempts-have-failed.png?sfvrsn=f9578b63_2" alt="Dialog displaying action buttons after all reconnection attempts have failed" /></p><p>With the above, we have finished customizing the connection modal correctly.</p><h2 id="conclusion">Conclusion</h2><p>Throughout this article, you have learned more in depth about the <strong>ReconnectionModal</strong> component, which shows how to implement reconnection state handling in Blazor. Additionally, we have turned the default template into a visually elegant modern dialog. I encourage you to create your own version of the dialog to adapt it to your own applications.</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">Top 5 Components for Building AI-Powered Blazor Applications</h4></div><div class="col-8"><p class="u-fs16 u-mb0">These five components can help you leverage the power of <a target="_blank" href="https://www.telerik.com/blogs/top-5-components-building-ai-powered-blazor-applications">AI inside your Blazor app</a>.</p></div></div></aside><img src="https://feeds.telerik.com/link/23050/17288838.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:77ec49b2-cef0-464c-9416-0e3e7df1cfb5</id>
    <title type="text">Build Your Own AI Application Using Prebuilt Blazor Components</title>
    <summary type="text">With prebuilt components, you can easily build a Blazor application that connects to AI model services for chat conversations. Check it out.</summary>
    <published>2026-02-25T00:17:09Z</published>
    <updated>2026-06-14T09:54:16Z</updated>
    <author>
      <name>Héctor Pérez </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23050/17283200/build-your-own-ai-application-using-prebuilt-blazor-components"/>
    <content type="text"><![CDATA[<p><span class="featured">With prebuilt components, you can easily build a Blazor application that connects to AI model services for chat conversations. Check it out.</span></p><p>If you&rsquo;ve ever had the opportunity to use applications that allow you to converse with a large language model (an LLM) such as ChatGPT, Gemini, DeepSeek, etc., you know about the potential and usefulness they offer.</p><p>Additionally, if you&rsquo;re a software developer, you should know that there are APIs that allow you to create your own applications based on your requirements, making even better use of AI models in a personalized way. In this article, I will show you how to create your own AI application thanks to some pre-created components for Blazor.</p><h2 id="creating-the-chat-project-using-blazor">Creating the Chat Project Using Blazor</h2><p>The first step to creating your own chat application is to create a project using Blazor. In this case, let&rsquo;s use a <strong>Blazor Web App</strong> template, specifying an <strong>Interactive render mode</strong> equal to <strong>Server</strong> and an <strong>Interactivity location</strong> equal to <strong>Global</strong>.</p><p>Next, you should follow the <a target="_blank" href="https://www.telerik.com/blazor-ui/documentation/getting-started/web-app">Progress Telerik UI for Blazor components installation guide</a>, which consists of a wide variety of flexible and easy-to-use components that you can implement in just a few minutes to achieve a spectacular graphical interface.</p><h2 id="configuring-the-connection-to-an-ai-model-service">Configuring the Connection to an AI Model Service</h2><p>Once the project has been created, you need to configure a service that can be injected across the pages and that you can reuse to invoke your preferred AI service.</p><p>In this case, we will use <strong>Microsoft.Extensions.AI</strong>, which allows us to easily connect to both Azure OpenAI and OpenAI services, and there are even independent projects like Bruno Capuano&rsquo;s that <a target="_blank" href="https://github.com/elbruno/elbruno-extensions-ai-claude">allows the use of Claude models on Azure</a> using these extensions. In our case, we will install the packages:</p><ul><li><code>Azure.AI.OpenAI</code></li><li><code>Microsoft.Extensions.AI</code></li><li><code>Microsoft.Extensions.AIMicrosoft.Extensions.AI</code></li></ul><p>After installing the packages, we need to go to <code>Program.cs</code> to make the service configuration, which, if it&rsquo;s for OpenAI, can be done like this:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">var</span> key <span class="token operator">=</span> builder<span class="token punctuation">.</span>Configuration<span class="token punctuation">[</span><span class="token string">"OPENAI_API_KEY"</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><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    builder<span class="token punctuation">.</span>Services
        <span class="token punctuation">.</span><span class="token function">AddChatClient</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">OpenAIClient</span><span class="token punctuation">(</span>
            <span class="token keyword">new</span> <span class="token class-name">ApiKeyCredential</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">GetChatClient</span><span class="token punctuation">(</span><span class="token string">"gpt-4o-mini"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">AsIChatClient</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">else</span>
<span class="token punctuation">{</span>
    Debug<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token string">"Warning: OPENAI_API_KEY not configured. AI features will not be available."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Or if you prefer Azure OpenAI, the configuration would look like this:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">var</span> key <span class="token operator">=</span> builder<span class="token punctuation">.</span>Configuration<span class="token punctuation">[</span><span class="token string">"AZURE_OPENAI_API_KEY"</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><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    builder<span class="token punctuation">.</span>Services
        <span class="token punctuation">.</span><span class="token function">AddChatClient</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">AzureOpenAIClient</span><span class="token punctuation">(</span>
                <span class="token keyword">new</span> <span class="token class-name">Uri</span><span class="token punctuation">(</span><span class="token string">"https://your-endpoint.openai.azure.com/"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>            
            <span class="token keyword">new</span> <span class="token class-name">ApiKeyCredential</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">GetChatClient</span><span class="token punctuation">(</span><span class="token string">"gpt-4.1"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">AsIChatClient</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">else</span>
<span class="token punctuation">{</span>
    Debug<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token string">"Warning: AZURE_OPENAI_API_KEY not configured. AI features will not be available."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>With the AI model configuration ready, we can proceed to create the main graphical interface.</p><h2 id="initial-setup-of-the-chat-page">Initial Setup of the Chat Page</h2><p>The next step in the project is to create a new page component where we will implement the chat. In this new page, we will replace the content with the following:</p><pre class=" language-xml"><code class="prism  language-xml">@page "/chat"

@using Microsoft.Extensions.AI
@inject IChatClient ChatClient

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>PageTitle</span><span class="token punctuation">&gt;</span></span>AI Chat<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>PageTitle</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>In the code above, we are defining the route for the new page, as well as injecting a reference of type <code>IChatClient</code> (previously configured) using <code>ChatClient</code>. We also specify the title of the page, which you can change as you see fit.</p><h2 id="using-blazor-appbar-to-create-the-application-header">Using Blazor AppBar to Create the Application Header</h2><p>The first prebuilt component we will use is a <a target="_blank" href="https://www.telerik.com/blazor-ui/appbar">Blazor AppBar</a>, which allows us to define sections that can configure actions or visual elements to indicate some type of status in the application.</p><p>To add it, simply define a <code>TelerikAppBar</code> tag, specifying parameters such as <code>ThemeColor</code> and <code>Class</code>:</p><pre class=" language-xml"><code class="prism  language-xml"><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>d-flex flex-column bg-light rounded-3 overflow-hidden shadow-lg<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">80</span>vh<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>TelerikAppBar</span> <span class="token attr-name">ThemeColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.AppBar.ThemeColor.Dark<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>rounded-top flex-shrink-0<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>TelerikAppBar</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>As part of a <code>TelerikAppBar</code>, <code>AppBarSection</code> type tags must be created to define the sections of the AppBar. In the following example, I will show you how to define three <code>AppBarSection</code>s:</p><pre class=" language-xml"><code class="prism  language-xml">...
<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>TelerikAppBar</span> <span class="token attr-name">ThemeColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.AppBar.ThemeColor.Dark<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>rounded-top flex-shrink-0<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>AppBarSection</span> <span class="token attr-name">Class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex-grow-1<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>TelerikSvgIcon</span> <span class="token attr-name">Icon</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@SvgIcon.Comment<span class="token punctuation">"</span></span> <span class="token attr-name">Size</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.SvgIcon.Size.Large<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>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>fw-semibold fs-5 ms-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>MyOwnChat<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>AppBarSection</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>AppBarSection</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikDropDownList</span> <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ModelOptions<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">@bind-Value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@SelectedModel<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>180px<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">Size</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.DropDownList.Size.Small<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>TelerikDropDownList</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>AppBarSection</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>AppBarSection</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikButton</span> <span class="token attr-name">OnClick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ClearChat<span class="token punctuation">"</span></span>
                            <span class="token attr-name">Icon</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@SvgIcon.Trash<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>New conversation<span class="token punctuation">"</span></span>
                            <span class="token attr-name">ThemeColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.Button.ThemeColor.Light<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>TelerikButton</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>AppBarSection</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikAppBar</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{
    private List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">&gt;</span></span> ModelOptions { get; set; } = new()
    {
        "GPT-5.2",
        "Gemini 2.5",
        "Claude Opus 4.5"
    };
    private string SelectedModel { get; set; } = "GPT-5.2";
    
    private void ClearChat()
    {
    }
}
</code></pre><p>In the code above, the <code>AppBarSection</code>s show the following:</p><ol><li>The first one defines the name of the application.</li><li>The second shows a dropdown that allows selecting an LLM, in case multiple options are available (in the app it works demonstratively).</li><li>The last one allows clearing the conversation.</li></ol><p>Additionally, you can also see the use of other very useful components such as the <a target="_blank" href="https://www.telerik.com/blazor-ui/dropdownlist">Blazor DropDownList</a>, which only needs to be bound to a list of strings, as well as a Button that allows executing actions. The result with just a few lines of code is as follows:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/using-the-telerik-appbar-component-to-display-information-in-a-blazor-chat-application.png?sfvrsn=1212c580_2" alt="Using the Telerik AppBar component to display information in a Blazor chat application" /></p><h2 id="building-an-initial-suggestions-list-using-components-for-blazor">Building an Initial Suggestions List Using Components for Blazor</h2><p>The main part of the chat section is divided into two parts. The first determines whether the user has previously interacted with the AI model. This can be done by defining a list of <code>ChatMessage</code>s where the conversation history will be accumulated. If this list is empty, we can make use of a <a target="_blank" href="https://www.telerik.com/blazor-ui/card">Blazor Card</a> that appears in the center with predefined prompt suggestions.</p><p>We can start by defining a <code>CardHeader</code> that displays an icon and some welcome text:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikCard</span> <span class="token attr-name">Class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>shadow border-0<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>CardHeader</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>CardTitle</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikSvgIcon</span> <span class="token attr-name">Icon</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@SvgIcon.Sparkles<span class="token punctuation">"</span></span> <span class="token attr-name">Size</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.SvgIcon.Size.ExtraLarge<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>span</span><span class="token punctuation">&gt;</span></span>How can I help you today?<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>CardTitle</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>CardHeader</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikCard</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Next, we need to build the body of the card using the <code>CardBody</code> tag. It is important to mention that this component is highly flexible and allows you to insert other components within it, making the interface as complex as you wish.</p><p>For example, we have used a <a target="_blank" href="https://www.telerik.com/blazor-ui/tilelayout">Blazor TileLayout</a> component to define multiple options for the user to press, which is fully configurable. Additionally, you can configure the <code>TileLayoutItems</code> tag within a <code>TelerikTileLayout</code>, where you can define the content for each of these elements.</p><p>In our case, we combined the use of a <a target="_blank" href="https://www.telerik.com/blazor-ui/buttons">Blazor Button</a> together with a <code>span</code> to display the content, resulting in the final code as follows:</p><pre class=" language-xml"><code class="prism  language-xml"><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>flex-grow-1 bg-white position-relative<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">min-height</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span></span><span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    @if (ChatData.Count == 0)
    {
        @* Welcome screen when there are no messages *@
        <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>d-flex align-items-center justify-content-center h-100 p-4 bg-light<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 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">max-width</span><span class="token punctuation">:</span> <span class="token number">700</span>px<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> <span class="token number">100%</span><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>TelerikCard</span> <span class="token attr-name">Class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>shadow border-0<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>CardHeader</span><span class="token punctuation">&gt;</span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>CardTitle</span><span class="token punctuation">&gt;</span></span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikSvgIcon</span> <span class="token attr-name">Icon</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@SvgIcon.Sparkles<span class="token punctuation">"</span></span> <span class="token attr-name">Size</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.SvgIcon.Size.ExtraLarge<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>span</span><span class="token punctuation">&gt;</span></span>How can I help you today?<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>CardTitle</span><span class="token punctuation">&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>CardHeader</span><span class="token punctuation">&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>CardBody</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 attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-secondary fs-5 mb-4 lh-base text-center<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                            I'm your AI assistant. I can help you with questions, analysis, creative writing, and much more.
                        <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>TelerikTileLayout</span> <span class="token attr-name">Columns</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span>
                                           <span class="token attr-name">ColumnWidth</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>100%<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>auto<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>false<span class="token punctuation">"</span></span>
                                           <span class="token attr-name">Resizable</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>false<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>mt-3<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>TileLayoutItems</span><span class="token punctuation">&gt;</span></span>
                                @foreach (var suggestion in QuickSuggestions)
                                {
                                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TileLayoutItem</span><span class="token punctuation">&gt;</span></span>
                                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Content</span><span class="token punctuation">&gt;</span></span>
                                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikButton</span> <span class="token attr-name">OnClick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@(() =&gt; UseSuggestion(suggestion.Text))<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>w-100 text-start d-flex align-items-center gap-2 p-3 border rounded-3<span class="token punctuation">"</span></span>
                                                           <span class="token attr-name">ThemeColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.Button.ThemeColor.Base<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>TelerikSvgIcon</span> <span class="token attr-name">Icon</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@suggestion.Icon<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>span</span><span class="token punctuation">&gt;</span></span>@suggestion.Text<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>TelerikButton</span><span class="token punctuation">&gt;</span></span>
                                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Content</span><span class="token punctuation">&gt;</span></span>
                                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TileLayoutItem</span><span class="token punctuation">&gt;</span></span>
                                }
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TileLayoutItems</span><span class="token punctuation">&gt;</span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikTileLayout</span><span class="token punctuation">&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>CardBody</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikCard</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>
    }
    else
    {
        
    }
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

@code{

    private List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ChatMessage</span><span class="token punctuation">&gt;</span></span> ChatData { get; set; } = new();
    private List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>SuggestionItem</span><span class="token punctuation">&gt;</span></span> QuickSuggestions { get; set; } = new()
    {
        new SuggestionItem { Text = "Explain a concept simply", Icon = SvgIcon.Book },
        new SuggestionItem { Text = "Write a professional email", Icon = SvgIcon.Envelope },
        new SuggestionItem { Text = "Get creative project ideas", Icon = SvgIcon.Palette },
        new SuggestionItem { Text = "Review and improve code", Icon = SvgIcon.Code }
    };

    private async Task UseSuggestion(string suggestion)
    {
        
    }
    ...
    public class SuggestionItem
    {
        public string Text { get; set; } = string.Empty;
        public ISvgIcon Icon { get; set; } = SvgIcon.Star;
    }
}
...
</code></pre><p>The result of rendering with the previous changes gives us the following:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/creating-an-initial-suggestions-list-in-an-ai-powered-chat-app-using-prebuilt-telerik-components.png?sfvrsn=f9d2d880_2" alt="Creating an initial suggestions list in an AI-powered chat app using prebuilt Telerik components" /></p><p>You can see that the application begins to take shape, showing an initial suggestions section for the user to interact with the LLM as quickly as possible.</p><h2 id="sending-messages-to-the-llm">Sending Messages to the LLM</h2><p>At this point, let&rsquo;s make the initial suggestion buttons send an instruction to the chat section. To do this, we will define some pieces of code that will be necessary for the graphical interface to function:</p><p><strong>Properties:</strong></p><ul><li><code>IsProcessing</code>: Property to indicate to the application whether a request is being processed to the AI model.</li><li><code>CurrentUserId</code>: ID of the current user. While we will set it as <em>user</em>, you could adapt it for the user to input their own nickname.</li><li><code>ConversationHistory</code>: A second list that allows interaction with the service that hosts the LLM. We use this because <code>ChatData</code> has an incompatible structure with the methods within <code>Microsoft.Extensions.AI</code>.</li><li><code>ChatSuggestions</code>: List that will be used by the Chat component to show the user prompt suggestions they can use during the conversation.</li></ul><p><strong>Methods:</strong></p><ul><li><code>UseSuggestion</code>: Method used from each <code>TelerikButton</code> defined in <code>TelerikTileLayout</code>, which invokes the <code>OnSendMessage</code> method.</li><li><code>OnSendMessage</code>: This is where the magic happens. The method serves to mark <code>IsProcessing</code> as true, indicating that processing of the prompt has started. Then, two elements of type <code>ChatMessage</code> are generated, the first called <code>userMessage</code>, which defines the user&rsquo;s query, and the second called <code>aiTypingMessage</code>, which will contain the response from the AI model. Next, within a <code>try</code>/<code>catch</code>/<code>finally</code>, the AI model service is invoked and the information in <code>aiTypingMessage</code> is updated.</li><li><code>UpdateSuggestions</code>: Method that allows updating the suggestions list <code>ChatSuggestions</code> that will be used by the Chat component in real time. These suggestions are fixed in the example, but you could modify the method to suggest a new list to the user based on the flow of information generated by AI.</li></ul><p><strong>Classes:</strong></p><ul><li><code>ChatMessage</code>: Class that will be used in the Chat component, allowing the management of information about a chat message such as the author&rsquo;s name, author&rsquo;s image, text, whether the status is typing, etc.</li></ul><p>The code updates are as follows:</p><pre class=" language-csharp"><code class="prism  language-csharp">@code<span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">bool</span> IsProcessing <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">false</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">string</span> CurrentUserId <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token string">"user"</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> List<span class="token operator">&lt;</span>Microsoft<span class="token punctuation">.</span>Extensions<span class="token punctuation">.</span>AI<span class="token punctuation">.</span>ChatMessage<span class="token operator">&gt;</span> ConversationHistory <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> List<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token operator">&gt;</span> ChatSuggestions <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">new</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">private</span> <span class="token keyword">async</span> Task <span class="token function">UseSuggestion</span><span class="token punctuation">(</span><span class="token keyword">string</span> suggestion<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">var</span> args <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ChatSendMessageEventArgs</span> <span class="token punctuation">{</span> Message <span class="token operator">=</span> suggestion <span class="token punctuation">}</span><span class="token punctuation">;</span>
        <span class="token keyword">await</span> <span class="token function">OnSendMessage</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">async</span> Task <span class="token function">OnSendMessage</span><span class="token punctuation">(</span>ChatSendMessageEventArgs args<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">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>args<span class="token punctuation">.</span>Message<span class="token punctuation">)</span> <span class="token operator">||</span> IsProcessing<span class="token punctuation">)</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>

        IsProcessing <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">;</span>
        
        <span class="token keyword">var</span> userMessage <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ChatMessage</span>
        <span class="token punctuation">{</span>
            Id <span class="token operator">=</span> Guid<span class="token punctuation">.</span><span class="token function">NewGuid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            AuthorId <span class="token operator">=</span> CurrentUserId<span class="token punctuation">,</span>
            AuthorName <span class="token operator">=</span> <span class="token string">"You"</span><span class="token punctuation">,</span>
            AuthorImageUrl <span class="token operator">=</span> <span class="token string">"https://api.dicebear.com/7.x/avataaars/svg?seed=user"</span><span class="token punctuation">,</span>
            Text <span class="token operator">=</span> args<span class="token punctuation">.</span>Message<span class="token punctuation">,</span>
            Timestamp <span class="token operator">=</span> DateTime<span class="token punctuation">.</span>Now<span class="token punctuation">,</span>
            Status <span class="token operator">=</span> <span class="token string">"Sent"</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
        ChatData<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>userMessage<span class="token punctuation">)</span><span class="token punctuation">;</span>
        
        ConversationHistory<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Microsoft<span class="token punctuation">.</span>Extensions<span class="token punctuation">.</span>AI<span class="token punctuation">.</span>ChatMessage</span><span class="token punctuation">(</span>ChatRole<span class="token punctuation">.</span>User<span class="token punctuation">,</span> args<span class="token punctuation">.</span>Message<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        
        <span class="token keyword">var</span> aiTypingMessage <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ChatMessage</span>
        <span class="token punctuation">{</span>
            Id <span class="token operator">=</span> Guid<span class="token punctuation">.</span><span class="token function">NewGuid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            AuthorId <span class="token operator">=</span> <span class="token string">"ai"</span><span class="token punctuation">,</span>
            AuthorName <span class="token operator">=</span> <span class="token string">"AI Assistant"</span><span class="token punctuation">,</span>
            AuthorImageUrl <span class="token operator">=</span> <span class="token string">"https://api.dicebear.com/7.x/bottts/svg?seed=ai"</span><span class="token punctuation">,</span>
            Text <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">,</span>
            Timestamp <span class="token operator">=</span> DateTime<span class="token punctuation">.</span>Now<span class="token punctuation">,</span>
            IsTyping <span class="token operator">=</span> <span class="token keyword">true</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
        ChatData<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>aiTypingMessage<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">RefreshChat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">try</span>
        <span class="token punctuation">{</span>            
            <span class="token keyword">var</span> response <span class="token operator">=</span> <span class="token keyword">await</span> ChatClient<span class="token punctuation">.</span><span class="token function">GetResponseAsync</span><span class="token punctuation">(</span>ConversationHistory<span class="token punctuation">)</span><span class="token punctuation">;</span>
            
            aiTypingMessage<span class="token punctuation">.</span>IsTyping <span class="token operator">=</span> <span class="token keyword">false</span><span class="token punctuation">;</span>
            aiTypingMessage<span class="token punctuation">.</span>Text <span class="token operator">=</span> response<span class="token punctuation">.</span>Text <span class="token operator">?</span><span class="token operator">?</span> <span class="token string">"Sorry, I couldn't generate a response."</span><span class="token punctuation">;</span>
            aiTypingMessage<span class="token punctuation">.</span>Status <span class="token operator">=</span> <span class="token string">"Delivered"</span><span class="token punctuation">;</span>
            
            ConversationHistory<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Microsoft<span class="token punctuation">.</span>Extensions<span class="token punctuation">.</span>AI<span class="token punctuation">.</span>ChatMessage</span><span class="token punctuation">(</span>ChatRole<span class="token punctuation">.</span>Assistant<span class="token punctuation">,</span> aiTypingMessage<span class="token punctuation">.</span>Text<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token function">UpdateSuggestions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token function">ShowNotification</span><span class="token punctuation">(</span><span class="token string">"Response received"</span><span class="token punctuation">,</span> ThemeConstants<span class="token punctuation">.</span>Notification<span class="token punctuation">.</span>ThemeColor<span class="token punctuation">.</span>Success<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><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            aiTypingMessage<span class="token punctuation">.</span>IsTyping <span class="token operator">=</span> <span class="token keyword">false</span><span class="token punctuation">;</span>
            aiTypingMessage<span class="token punctuation">.</span>Text <span class="token operator">=</span> $<span class="token string">"Error processing the request: {ex.Message}"</span><span class="token punctuation">;</span>
            aiTypingMessage<span class="token punctuation">.</span>Status <span class="token operator">=</span> <span class="token string">"Error"</span><span class="token punctuation">;</span>

            <span class="token function">ShowNotification</span><span class="token punctuation">(</span><span class="token string">"Processing error"</span><span class="token punctuation">,</span> ThemeConstants<span class="token punctuation">.</span>Notification<span class="token punctuation">.</span>ThemeColor<span class="token punctuation">.</span>Error<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">finally</span>
        <span class="token punctuation">{</span>
            IsProcessing <span class="token operator">=</span> <span class="token keyword">false</span><span class="token punctuation">;</span>
            <span class="token function">RefreshChat</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">private</span> <span class="token keyword">void</span> <span class="token function">ClearChat</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 keyword">void</span> <span class="token function">RefreshChat</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 keyword">void</span> <span class="token function">ShowNotification</span><span class="token punctuation">(</span><span class="token keyword">string</span> message<span class="token punctuation">,</span> <span class="token keyword">string</span> themeColor<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
    <span class="token punctuation">}</span>

    
    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">UpdateSuggestions</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>ChatData<span class="token punctuation">.</span>Count <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            ChatSuggestions <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">List</span><span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token operator">&gt;</span>
            <span class="token punctuation">{</span>
                <span class="token string">"What can you do?"</span><span class="token punctuation">,</span>
                <span class="token string">"Tell me a fun fact"</span><span class="token punctuation">,</span>
                <span class="token string">"Help me with code"</span>
            <span class="token punctuation">}</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">else</span>
        <span class="token punctuation">{</span>
            ChatSuggestions <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">List</span><span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token operator">&gt;</span>
            <span class="token punctuation">{</span>
                <span class="token string">"Continue"</span><span class="token punctuation">,</span>
                <span class="token string">"Explain more"</span><span class="token punctuation">,</span>
                <span class="token string">"Give me an example"</span><span class="token punctuation">,</span>
                <span class="token string">"Summarize please"</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">public</span> <span class="token keyword">class</span> <span class="token class-name">ChatMessage</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">public</span> <span class="token keyword">string</span> Id <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span>
        <span class="token keyword">public</span> <span class="token keyword">string</span> AuthorId <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span>
        <span class="token keyword">public</span> <span class="token keyword">string</span> AuthorName <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span>
        <span class="token keyword">public</span> <span class="token keyword">string</span> AuthorImageUrl <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span>
        <span class="token keyword">public</span> <span class="token keyword">string</span> Text <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span>
        <span class="token keyword">public</span> DateTime Timestamp <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
        <span class="token keyword">public</span> <span class="token keyword">string</span> Status <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span>
        <span class="token keyword">public</span> <span class="token keyword">bool</span> IsTyping <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
        <span class="token keyword">public</span> <span class="token keyword">bool</span> IsPinned <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</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 execution of the application gives us the following result:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/the-chat-application-built-with-prebuilt-components-ready-to-display-a-conversation-with-an-ai-model.gif?sfvrsn=8bdbae4_2" alt="The chat application built with prebuilt components, ready to display a conversation with an AI model" /></p><p>In the previous image, you can see the transition that occurs when there are elements in ChatData, which would allow the Chat component to be displayed.</p><h2 id="defining-the-chat-section">Defining the Chat Section</h2><p>In the previous section, we left everything set up to start a chat conversation. Now, we&rsquo;re going to use the <a target="_blank" href="https://www.telerik.com/blazor-ui/chat-(conversational-ui)">Blazor Chat</a> component from Progress Telerik to manage the conversation with the LLM in a straightforward way, as this component is highly customizable and has all the necessary functionality for rapid implementation.</p><p>The code we&rsquo;ll add in the UI is as follows:</p><pre class=" language-xml"><code class="prism  language-xml">else
{    
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikChat</span> <span class="token attr-name">@ref</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ChatRef<span class="token punctuation">"</span></span>
                 <span class="token attr-name">TItem</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ChatMessage<span class="token punctuation">"</span></span>
                 <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ChatData<span class="token punctuation">"</span></span>
                 <span class="token attr-name">AuthorId</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@CurrentUserId<span class="token punctuation">"</span></span>
                 <span class="token attr-name">OnSendMessage</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@OnSendMessage<span class="token punctuation">"</span></span>
                 <span class="token attr-name">Suggestions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ChatSuggestions<span class="token punctuation">"</span></span>
                 <span class="token attr-name">OnSuggestionClick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@OnSuggestionClick<span class="token punctuation">"</span></span>
                 <span class="token attr-name">SuggestionsLayoutMode</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ChatSuggestionsLayoutMode.ScrollButtons<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>100%<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>100%<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>border-0 bg-white<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>HeaderTemplate</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>d-flex align-items-center gap-3 px-3 py-2 bg-light border-bottom<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>TelerikChip</span> <span class="token attr-name">Size</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.Chip.Size.Small<span class="token punctuation">"</span></span>
                             <span class="token attr-name">ThemeColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.Chip.ThemeColor.Success<span class="token punctuation">"</span></span>
                             <span class="token attr-name">Rounded</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.Chip.Rounded.Full<span class="token punctuation">"</span></span>
                             <span class="token attr-name">Icon</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@SvgIcon.CheckCircle<span class="token punctuation">"</span></span>
                             <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Connected<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>TelerikChip</span><span class="token punctuation">&gt;</span></span>
                <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>small text-secondary<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@ChatData.Count messages<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>HeaderTemplate</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ReceiverMessageContentTemplate</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>lh-lg<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                @if (context.Message.IsTyping)
                {
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikLoader</span> <span class="token attr-name">Size</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.Loader.Size.Small<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>TelerikLoader</span><span class="token punctuation">&gt;</span></span>
                    <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>ms-2 text-secondary fst-italic<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Thinking...<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
                }
                else
                {
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>MarkdownContent</span> <span class="token attr-name">Message</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@context.Message.Text<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 tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ReceiverMessageContentTemplate</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>AuthorMessageContentTemplate</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>lh-lg<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                @context.Message.Text
            <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>AuthorMessageContentTemplate</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>NoDataTemplate</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>d-flex flex-column align-items-center justify-content-center p-5 text-secondary<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>TelerikSvgIcon</span> <span class="token attr-name">Icon</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@SvgIcon.Comment<span class="token punctuation">"</span></span> <span class="token attr-name">Size</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.SvgIcon.Size.ExtraLarge<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 attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mt-3 fs-5<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>No messages yet. Start a conversation!<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 punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>NoDataTemplate</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikChat</span><span class="token punctuation">&gt;</span></span>
}
</code></pre><p>In the code above, as part of the <code>else</code> that is shown if <code>ChatData</code> contains items, a <code>TelerikChat</code> bound to <code>ChatData</code> is created, which contains all the conversation information. Additionally, properties such as <code>Suggestions</code>, <code>AuthorId</code>, among others, are used to configure the component.</p><p>In addition to configuring the component through parameters, other tags like <code>HeaderTemplate</code> can also be defined to display the connection status to the service, as well as the number of messages within the conversation.</p><p><code>ReceiverMessageContentTemplate</code> is also used to define the content depending on the status of the request to the AI service. If the message is awaited, a <a target="_blank" href="https://www.telerik.com/blazor-ui/loader">Blazor Loader</a> component is used to show a loading state. If a response is available, the content is displayed in the chat.</p><p>At this point, we have defined a component called <code>MarkdownContent</code>, which is based on the NuGet package <a target="_blank" href="https://github.com/xoofx/markdig"><code>Markdig</code></a> that allows converting the markdown text received from the LLM into a <code>HTML</code> version, enabling the correct format for each markdown element in the conversation.</p><p>In addition to the above, <code>AuthorMessageContentTemplate</code> is also specified to define the template for user messages and <code>NoDataTemplate</code> in case we want to show content when there are no chat messages in the conversation.</p><p>In the code section, we need to add a reference to the component <code>TelerikChat</code>, which allows us to execute the method <code>Refresh</code> from the method <code>RefreshChat</code>, in addition to the event handler definition <code>OnSuggestionClick</code>, which allows handling the suggestions from the component (different from the options at the beginning of execution), as follows:</p><pre class=" language-csharp"><code class="prism  language-csharp">@code<span class="token punctuation">{</span>

    <span class="token keyword">private</span> TelerikChat<span class="token operator">&lt;</span>ChatMessage<span class="token operator">&gt;</span><span class="token operator">?</span> ChatRef <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">async</span> Task <span class="token function">OnSuggestionClick</span><span class="token punctuation">(</span>ChatSuggestionClickEventArgs args<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">await</span> <span class="token function">UseSuggestion</span><span class="token punctuation">(</span>args<span class="token punctuation">.</span>Suggestion<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">private</span> <span class="token keyword">void</span> <span class="token function">RefreshChat</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        ChatRef<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">Refresh</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">StateHasChanged</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>With the code above, we already have a Chat section that allows us to interact with an LLM:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/the-chat-app-displaying-the-telerikchat-component-enabling-conversations-with-an-llm-model.gif?sfvrsn=8bdaa5dc_2" alt="The chat app displaying the TelerikChat component, enabling conversations with an LLM" /></p><p>With this, you have been able to see that the chat implementation is already working correctly.</p><h2 id="creating-a-toolbar-like-footer">Creating a ToolBar-like Footer</h2><p>The last section we will work on is the footer. We will do this using a <a target="_blank" href="https://www.telerik.com/blazor-ui/toolbar">Blazor ToolBar</a>, which allows us to add a toolbar for buttons, separators, and even custom content. Our code looks as follows:</p><pre class=" language-xml"><code class="prism  language-xml"><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>bg-white border-top flex-shrink-0<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>TelerikToolBar</span> <span class="token attr-name">Class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-transparent border-0 px-3 py-2<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>ToolBarButton</span> <span class="token attr-name">Icon</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@SvgIcon.InfoCircle<span class="token punctuation">"</span></span> <span class="token attr-name">OnClick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ShowAboutDialog<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>About<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ToolBarButton</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ToolBarSeparator</span> <span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ToolBarTemplateItem</span><span class="token punctuation">&gt;</span></span>
            <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>d-flex align-items-center gap-1 text-secondary small<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>TelerikSvgIcon</span> <span class="token attr-name">Icon</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@SvgIcon.Clock<span class="token punctuation">"</span></span> <span class="token attr-name">Size</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.SvgIcon.Size.Small<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                @DateTime.Now.ToString("HH:mm")
            <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>ToolBarTemplateItem</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ToolBarSpacer</span> <span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ToolBarTemplateItem</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikChip</span> <span class="token attr-name">ThemeColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.Chip.ThemeColor.Info<span class="token punctuation">"</span></span>
                            <span class="token attr-name">Rounded</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.Chip.Rounded.Full<span class="token punctuation">"</span></span>
                            <span class="token attr-name">Size</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ThemeConstants.Chip.Size.Small<span class="token punctuation">"</span></span>
                            <span class="token attr-name">Selectable</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>false<span class="token punctuation">"</span></span>
                            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@SelectedModel<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>TelerikChip</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ToolBarTemplateItem</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikToolBar</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 {

    private bool ShowAboutDialogVisible { get; set; } = false;

    private void ShowAboutDialog()
    {
        ShowAboutDialogVisible = true;
    }
    ...
}
</code></pre><p>In the code above, we see the following elements in sequence:</p><ul><li><code>ToolBarButton</code> to display a button that we can press to show an information window about the app.</li><li><code>ToolBarSeparator</code> to display a separator line between elements.</li><li><code>ToolBarTemplateItem</code> to show custom content, specifically the current time.</li><li><code>ToolBarSpacer</code> to push the subsequent elements to the right of the main control.</li><li><code>ToolBarTemplateItem</code> to display custom content. In this case, we are using a <a target="_blank" href="https://www.telerik.com/blazor-ui/chip"><code>TelerikChip</code></a>, which allows displaying tag-like elements that we use to show the selected model.</li></ul><p>In addition to the above, we have prepared the logic to display application information through the definition of the <code>ShowAboutDialogVisible</code> property and the <code>ShowAboutDialog</code> method.</p><p>The result of running the application after applying the changes is as follows:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/implementing-a-toolbar-in-the-chat-application-using-the-teleriktoolbar-component.png?sfvrsn=c99acbd2_2" alt="Implementing a toolbar in the chat application using the TelerikToolBar component" /></p><h2 id="displaying-application-information">Displaying Application Information</h2><p>In most applications, it is essential to be able to show application information to users, whether to specify the version, usage quotas, payment information, etc. We can easily achieve this by using the <a target="_blank" href="https://www.telerik.com/blazor-ui/dialog">Blazor Dialog</a> component, which we can show and hide at will, customizing its content thanks to the <code>DialogContent</code> tag.</p><p>In our case, we used a <code>TelerikCard</code> to show information about the application as follows:</p><pre><code>...
&lt;TelerikDialog @bind-Visible="@ShowAboutDialogVisible"
               Title="About MyOwnChat"
               Width="400px"&gt;
    &lt;DialogContent&gt;
        &lt;TelerikCard&gt;
            &lt;CardBody&gt;
                &lt;div class="text-center p-3"&gt;
                    &lt;TelerikSvgIcon Icon="@SvgIcon.Sparkles" Size="@ThemeConstants.SvgIcon.Size.ExtraLarge" /&gt;
                    &lt;h3 class="mt-3 mb-2"&gt;MyOwnChat&lt;/h3&gt;
                    &lt;p class="text-secondary mb-4"&gt;An AI-powered chat interface, built with Blazor and Telerik UI.&lt;/p&gt;
                    &lt;TelerikChipList Data="@AboutChips"
                                     SelectionMode="@ChipListSelectionMode.None"&gt;
                    &lt;/TelerikChipList&gt;
                &lt;/div&gt;
            &lt;/CardBody&gt;
        &lt;/TelerikCard&gt;
    &lt;/DialogContent&gt;
    &lt;DialogButtons&gt;
        &lt;TelerikButton OnClick="@(() =&gt; ShowAboutDialogVisible = false)"
                       ThemeColor="@ThemeConstants.Button.ThemeColor.Dark"&gt;
            Close
        &lt;/TelerikButton&gt;
    &lt;/DialogButtons&gt;
&lt;/TelerikDialog&gt;

@code {


    private List&lt;ChipItem&gt; AboutChips { get; set; } = new()
    {
        new ChipItem { Text = "Blazor" },
        new ChipItem { Text = "Telerik UI" },
        new ChipItem { Text = "AI Powered" }
    };

    ...

    public class ChipItem
    {
        public string Text { get; set; } = string.Empty;
    }
}
</code></pre><p>The previous code results in the following interaction:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/displaying-chat-application-information-in-a-separate-dialog-using-the-telerikdialog-component.gif?sfvrsn=328d3802_2" alt="Displaying chat application information in a separate dialog using the TelerikDialog component" /></p><p>Now, let&rsquo;s look at the last component that allows us to show notifications.</p><h2 id="displaying-notifications-in-the-blazor-chat-app">Displaying Notifications in the Blazor Chat App</h2><p>The last component we will use for our chat application is <a target="_blank" href="https://www.telerik.com/blazor-ui/notification">Blazor Notification</a>, which allows displaying notifications to users to keep them informed about the status of actions in the application. Defining it is very simple:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikNotification</span> <span class="token attr-name">@ref</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@NotificationRef<span class="token punctuation">"</span></span>
                     <span class="token attr-name">VerticalPosition</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@NotificationVerticalPosition.Top<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>TelerikNotification</span><span class="token punctuation">&gt;</span></span>

@code {

    private TelerikNotification? NotificationRef { get; set; }
    ...
    private void ShowNotification(string message, string themeColor)
    {
        NotificationRef?.Show(new NotificationModel
        {
            Text = message,
            ThemeColor = themeColor,
            CloseAfter = 3000
        });
    }
}
</code></pre><p>In the code above, the <code>TelerikNotification</code> tag is defined by assigning the <code>@ref</code> parameter a property defined in the code, which allows displaying a notification. Within <code>ShowNotification</code>, the <code>Show</code> method is invoked, where we specify the message to display, color and how long the notification should be shown:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/displaying-notifications-in-the-chat-app-using-the-teleriknotification-component.png?sfvrsn=8bf3416e_2" alt="Displaying notifications in the chat app using the TelerikNotification component" /></p><h2 id="clearing-the-chat">Clearing the Chat</h2><p>To finish the application, we will complete the implementation of the <code>ClearChat</code> method so that the user can restart a conversation from scratch:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">ClearChat</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    ChatData<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>
    ConversationHistory<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 function">UpdateSuggestions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">ShowNotification</span><span class="token punctuation">(</span><span class="token string">"Conversation cleared"</span><span class="token punctuation">,</span> ThemeConstants<span class="token punctuation">.</span>Notification<span class="token punctuation">.</span>ThemeColor<span class="token punctuation">.</span>Info<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>In the code above, the conversation lists are reset, the suggestions are updated with the initials, and a message is displayed to the user regarding the clearing of conversations.</p><h2 id="conclusion">Conclusion</h2><p>Throughout this article, we have selected prebuilt Telerik components for Blazor that allowed us to create a chat application that connects to AI model services for chat conversations.</p><p>Using prebuilt components helps make your development faster by providing a wide list of parameters that assist in customizing the graphical interface, as we have seen throughout the article. Additionally, you can be assured that the components are robust and are constantly updated, improving them through user feedback.</p><p>If you aren't already using Telerik UI for Blazor, you can try it free for 30 days:</p><p><a href="https://www.telerik.com/try/ui-for-blazor" target="_blank" class="Btn">Try Now</a></p><img src="https://feeds.telerik.com/link/23050/17283200.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:6424c9d1-f6fa-4231-9a0c-5ebc5fbe5b6f</id>
    <title type="text">Creating Drag-and-Drop ListBoxes in Blazor</title>
    <summary type="text">See how the Telerik UI for Blazor ListBox makes implementing dragging and dropping items between lists easy—based on a real-life case!</summary>
    <published>2026-02-16T17:12:19Z</published>
    <updated>2026-06-14T09:54:16Z</updated>
    <author>
      <name>Héctor Pérez </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23050/17277349/creating-drag-drop-listboxes-blazor"/>
    <content type="text"><![CDATA[<p><span class="featured">See how the Telerik UI for Blazor ListBox makes implementing dragging and dropping items between lists easy&mdash;based on a real-life case!</span></p><p>There are applications that require very specific use cases to solve real problems. One such case is the need to implement functionality to drag and drop items between different list-like controls.</p><p>This functionality can be found natively in the <a target="_blank" href="https://www.telerik.com/blazor-ui/listbox">Blazor ListBox</a> component from Progress Telerik, making it an excellent option in these scenarios, which is why I will show you how to implement drag and drop between several components of this type.</p><h2 id="dragging-items-between-listboxes-in-blazor-a-practical-case">Dragging Items Between ListBoxes in Blazor: A Practical Case</h2><p>I have to admit that the idea for this post was born from a real-life case, which I will share to provide you with its background. I teach online software development courses, several of which are hosted on a fairly popular platform. This platform offers instructors the convenience of creating coupons using a graphical interface from the dashboard of a particular course.</p><p>The problem arises when the instructor has many courses on the platform and wants to create coupons in bulk quickly. The platform has a system based on <code>.csv</code> files to solve this problem, although it is not the best option for someone who is not involved in the technology field.</p><p>The first <code>.csv</code> file provided by the platform is a file containing the list of all the instructor&rsquo;s courses, from which data such as course ID, course name, among other data can be extracted, and it looks like this:</p><pre class=" language-csv"><code class="prism  language-csv">"course_id","course_name","currency","best_price_value","min_custom_price","max_custom_price","coupons_remaining"
1234567,".NET MAUI: Advanced UI and Custom Control Techniques","USD",9.99,12.99,79.99,3
</code></pre><p>The second <code>.csv</code> file provided is a template to fill in the information for the coupons to be created, in which information such as the discount to be applied, course ID, coupon start date, among other data must be included:</p><pre class=" language-csv"><code class="prism  language-csv">course_id,coupon_type,coupon_code,price,start_date,start_time,custom_price
1234567,best_price,DEVJUN1,9.99,2025-06-16,19:44,
</code></pre><p>Now, here comes the important part. The data <code>coupon_type</code> specifies whether the coupon is paid or free, specified in four possible values:</p><ul><li>best_price</li><li>custom_price</li><li>free_targeted</li><li>free_open</li></ul><p>Once the csv template is filled with the courses that will have a coupon applied, it can be uploaded on the same portal for the bulk generation of the coupons. The previous process can be quite complicated for instructors not involved in technology, which we can simplify thanks to the use of the Telerik UI for Blazor ListBox component.</p><h2 id="creating-a-component-page-using-listbox">Creating a Component Page Using ListBox</h2><p>The ListBox component is a quite powerful tool that allows you to display lists of selectable, reorderable, deletable items and more. One thing I really like about this component is that you can customize it as much as you want through the tag <code>ItemTemplate</code>.</p><p>For our demonstration, I have created a page-type component applying various styles, so you can see the potential of using the ListBox component in action:</p><pre class=" language-xml"><code class="prism  language-xml">@page "/"


<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>PageTitle</span><span class="token punctuation">&gt;</span></span>Drag &amp; Drop Demo<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>PageTitle</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikRootComponent</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>demo-container<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>demo-header<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>h2</span><span class="token punctuation">&gt;</span></span>Drag and Drop Demo<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>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>lists-container<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>source-column<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>list-card available-card<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>list-header<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>h4</span><span class="token punctuation">&gt;</span></span>Available Courses<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h4</span><span class="token punctuation">&gt;</span></span>
                        <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>badge<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@AvailableCourses.Count<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>TelerikListBox</span> <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@AvailableCourses<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">TextField</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@nameof(Course.Name)<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>400px<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>100%<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>ListBoxToolBarSettings</span><span class="token punctuation">&gt;</span></span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ListBoxToolBar</span> <span class="token attr-name">Visible</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>false<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>ListBoxToolBarSettings</span><span class="token punctuation">&gt;</span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ItemTemplate</span><span class="token punctuation">&gt;</span></span>
                            @{
                                var course = context;
                            }
                            <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>course-item<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>course-info<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>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>course-name<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@course.Name<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>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>course-price<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@course.Currency @course.Price.ToString("N2")<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>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>course-category<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@course.Category<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>ItemTemplate</span><span class="token punctuation">&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikListBox</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>
            <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>destination-columns<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>coupon-grid<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>list-card best-price-card<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>list-header<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>h4</span><span class="token punctuation">&gt;</span></span>Best Price<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h4</span><span class="token punctuation">&gt;</span></span>
                            <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>badge<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@BestPriceCourses.Count<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>TelerikListBox</span> <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@BestPriceCourses<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">TextField</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@nameof(Course.Name)<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>100%<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>200px<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>ListBoxToolBarSettings</span><span class="token punctuation">&gt;</span></span>
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ListBoxToolBar</span> <span class="token attr-name">Visible</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>false<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>ListBoxToolBarSettings</span><span class="token punctuation">&gt;</span></span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ItemTemplate</span><span class="token punctuation">&gt;</span></span>
                                @{
                                    var course = context;
                                }
                                <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>course-item-mini<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>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>course-name<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@course.Name<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>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>course-tag best-price<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@course.Currency @course.Price.ToString("N2")<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>ItemTemplate</span><span class="token punctuation">&gt;</span></span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>NoDataTemplate</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>no-data<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>span</span><span class="token punctuation">&gt;</span></span>Drop courses here<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>NoDataTemplate</span><span class="token punctuation">&gt;</span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikListBox</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>list-card custom-price-card<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>list-header<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>h4</span><span class="token punctuation">&gt;</span></span>Custom Price<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h4</span><span class="token punctuation">&gt;</span></span>
                            <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>badge<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@CustomPriceCourses.Count<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>TelerikListBox</span> <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@CustomPriceCourses<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">TextField</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@nameof(Course.Name)<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>100%<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>200px<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>ListBoxToolBarSettings</span><span class="token punctuation">&gt;</span></span>
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ListBoxToolBar</span> <span class="token attr-name">Visible</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>false<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>ListBoxToolBarSettings</span><span class="token punctuation">&gt;</span></span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ItemTemplate</span><span class="token punctuation">&gt;</span></span>
                                @{
                                    var course = context;
                                }
                                <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>course-item-mini<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>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>course-name<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@course.Name<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>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>course-tag custom-price<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@course.Currency @course.Price.ToString("N2")<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>ItemTemplate</span><span class="token punctuation">&gt;</span></span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>NoDataTemplate</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>no-data<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>span</span><span class="token punctuation">&gt;</span></span>Drop courses here<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>NoDataTemplate</span><span class="token punctuation">&gt;</span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikListBox</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>list-card free-open-card<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>list-header<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>h4</span><span class="token punctuation">&gt;</span></span>Free Open<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h4</span><span class="token punctuation">&gt;</span></span>
                            <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>badge<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@FreeOpenCourses.Count<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>TelerikListBox</span> <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@FreeOpenCourses<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">TextField</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@nameof(Course.Name)<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>100%<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>200px<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>ListBoxToolBarSettings</span><span class="token punctuation">&gt;</span></span>
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ListBoxToolBar</span> <span class="token attr-name">Visible</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>false<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>ListBoxToolBarSettings</span><span class="token punctuation">&gt;</span></span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ItemTemplate</span><span class="token punctuation">&gt;</span></span>
                                @{
                                    var course = context;
                                }
                                <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>course-item-mini<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>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>course-name<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@course.Name<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>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>course-tag free<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>FREE<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>ItemTemplate</span><span class="token punctuation">&gt;</span></span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>NoDataTemplate</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>no-data<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>span</span><span class="token punctuation">&gt;</span></span>Drop courses here<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>NoDataTemplate</span><span class="token punctuation">&gt;</span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikListBox</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>list-card free-targeted-card<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>list-header<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>h4</span><span class="token punctuation">&gt;</span></span>Free Targeted<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h4</span><span class="token punctuation">&gt;</span></span>
                            <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>badge<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@FreeTargetedCourses.Count<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>TelerikListBox</span> <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@FreeTargetedCourses<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">TextField</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@nameof(Course.Name)<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>100%<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>200px<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>ListBoxToolBarSettings</span><span class="token punctuation">&gt;</span></span>
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ListBoxToolBar</span> <span class="token attr-name">Visible</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>false<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>ListBoxToolBarSettings</span><span class="token punctuation">&gt;</span></span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ItemTemplate</span><span class="token punctuation">&gt;</span></span>
                                @{
                                    var course = context;
                                }
                                <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>course-item-mini<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>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>course-name<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>@course.Name<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>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>course-tag targeted<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>TARGETED<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>ItemTemplate</span><span class="token punctuation">&gt;</span></span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>NoDataTemplate</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>no-data<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>span</span><span class="token punctuation">&gt;</span></span>Drop courses here<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>NoDataTemplate</span><span class="token punctuation">&gt;</span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikListBox</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>
            <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>
    <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>TelerikRootComponent</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span><span class="token punctuation">&gt;</span></span><span class="token style language-css">
    <span class="token selector"><span class="token pseudo-class">:root</span> </span><span class="token punctuation">{</span>
        <span class="token property">--bg-color</span><span class="token punctuation">:</span> <span class="token hexcode">#1e1e1e</span><span class="token punctuation">;</span>
        <span class="token property">--bg-accent</span><span class="token punctuation">:</span> <span class="token hexcode">#252526</span><span class="token punctuation">;</span>
        <span class="token property">--card-glass</span><span class="token punctuation">:</span> <span class="token hexcode">#252526</span><span class="token punctuation">;</span>
        <span class="token property">--border-glass</span><span class="token punctuation">:</span> <span class="token hexcode">#3c3c3c</span><span class="token punctuation">;</span>
        <span class="token property">--accent-blue</span><span class="token punctuation">:</span> <span class="token hexcode">#4ec9b0</span><span class="token punctuation">;</span>
        <span class="token property">--accent-purple</span><span class="token punctuation">:</span> <span class="token hexcode">#c586c0</span><span class="token punctuation">;</span>
        <span class="token property">--accent-green</span><span class="token punctuation">:</span> <span class="token hexcode">#608b4e</span><span class="token punctuation">;</span>
        <span class="token property">--accent-amber</span><span class="token punctuation">:</span> <span class="token hexcode">#d7ba7d</span><span class="token punctuation">;</span>
        <span class="token property">--accent-red</span><span class="token punctuation">:</span> <span class="token hexcode">#f48771</span><span class="token punctuation">;</span>
        <span class="token property">--text-main</span><span class="token punctuation">:</span> <span class="token hexcode">#d4d4d4</span><span class="token punctuation">;</span>
        <span class="token property">--text-muted</span><span class="token punctuation">:</span> <span class="token hexcode">#858585</span><span class="token punctuation">;</span>
        <span class="token property">--shadow-soft</span><span class="token punctuation">:</span> <span class="token number">0</span> <span class="token number">8</span>px <span class="token number">16</span>px <span class="token function">rgba</span><span class="token punctuation">(</span><span class="token number">0</span>, <span class="token number">0</span>, <span class="token number">0</span>, <span class="token number">0.45</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">--radius-lg</span><span class="token punctuation">:</span> <span class="token number">10</span>px<span class="token punctuation">;</span>
        <span class="token property">--radius-md</span><span class="token punctuation">:</span> <span class="token number">8</span>px<span class="token punctuation">;</span>
        <span class="token property">--transition-fast</span><span class="token punctuation">:</span> <span class="token number">0.15</span>s ease-out<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.demo-container</span> </span><span class="token punctuation">{</span>
        <span class="token property">min-height</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token number">100</span>vh - <span class="token number">40</span>px<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">max-width</span><span class="token punctuation">:</span> <span class="token number">1440</span>px<span class="token punctuation">;</span>
        <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token number">0</span> auto<span class="token punctuation">;</span>
        <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token number">24</span>px <span class="token number">20</span>px <span class="token number">32</span>px<span class="token punctuation">;</span>
        <span class="token property">font-family</span><span class="token punctuation">:</span> system-ui, -apple-system, BlinkMacSystemFont, <span class="token string">'Segoe UI'</span>, sans-serif<span class="token punctuation">;</span>
        <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text-main<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span>
        <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--bg-color<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

        <span class="token selector"><span class="token class">.demo-container</span><span class="token pseudo-element">::before</span> </span><span class="token punctuation">{</span>
            <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">;</span>
            <span class="token property">position</span><span class="token punctuation">:</span> fixed<span class="token punctuation">;</span>
            <span class="token property">inset</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span>
            <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--bg-color<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token property">z-index</span><span class="token punctuation">:</span> -<span class="token number">2</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token selector"><span class="token class">.demo-container</span><span class="token pseudo-element">::after</span> </span><span class="token punctuation">{</span>
            <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">;</span>
            <span class="token property">position</span><span class="token punctuation">:</span> fixed<span class="token punctuation">;</span>
            <span class="token property">inset</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span>
            <span class="token property">background</span><span class="token punctuation">:</span> transparent<span class="token punctuation">;</span>
            <span class="token property">z-index</span><span class="token punctuation">:</span> -<span class="token number">1</span><span class="token punctuation">;</span>
            <span class="token property">pointer-events</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.demo-header</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">flex-direction</span><span class="token punctuation">:</span> column<span class="token punctuation">;</span>
        <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
        <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token number">6</span>px<span class="token punctuation">;</span>
        <span class="token property">margin-bottom</span><span class="token punctuation">:</span> <span class="token number">22</span>px<span class="token punctuation">;</span>
        <span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

        <span class="token selector"><span class="token class">.demo-header</span> h2 </span><span class="token punctuation">{</span>
            <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token number">1.9</span>rem<span class="token punctuation">;</span>
            <span class="token property">letter-spacing</span><span class="token punctuation">:</span> <span class="token number">0.02</span>em<span class="token punctuation">;</span>
            <span class="token property">font-weight</span><span class="token punctuation">:</span> <span class="token number">650</span><span class="token punctuation">;</span>
            <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text-main<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.demo-subtitle</span> </span><span class="token punctuation">{</span>
        <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token number">0.95</span>rem<span class="token punctuation">;</span>
        <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text-muted<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">max-width</span><span class="token punctuation">:</span> <span class="token number">620</span>px<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.lists-container</span> </span><span class="token punctuation">{</span>
        <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
        <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">minmax</span><span class="token punctuation">(</span><span class="token number">320</span>px, <span class="token number">360</span>px<span class="token punctuation">)</span> <span class="token function">minmax</span><span class="token punctuation">(</span><span class="token number">0</span>, <span class="token number">1</span>fr<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token number">18</span>px<span class="token punctuation">;</span>
        <span class="token property">align-items</span><span class="token punctuation">:</span> stretch<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.source-column</span>,
    <span class="token class">.destination-columns</span> </span><span class="token punctuation">{</span>
        <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span>
        <span class="token property">z-index</span><span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.list-card</span> </span><span class="token punctuation">{</span>
        <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--radius-lg<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-glass<span class="token punctuation">)</span><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 function">var</span><span class="token punctuation">(</span>--border-glass<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">box-shadow</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
        <span class="token property">backdrop-filter</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
        <span class="token property">-webkit-backdrop-filter</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
        <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span>
        <span class="token property">transition</span><span class="token punctuation">:</span> border-color <span class="token function">var</span><span class="token punctuation">(</span>--transition-fast<span class="token punctuation">)</span>, background-color <span class="token function">var</span><span class="token punctuation">(</span>--transition-fast<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.list-header</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">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
        <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token number">10</span>px<span class="token punctuation">;</span>
        <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token number">12</span>px <span class="token number">16</span>px <span class="token number">10</span>px<span class="token punctuation">;</span>
        <span class="token property">border-bottom</span><span class="token punctuation">:</span> <span class="token number">1</span>px solid <span class="token function">rgba</span><span class="token punctuation">(</span><span class="token number">148</span>, <span class="token number">163</span>, <span class="token number">184</span>, <span class="token number">0.3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

        <span class="token selector"><span class="token class">.list-header</span> h4 </span><span class="token punctuation">{</span>
            <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span>
            <span class="token property">flex</span><span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">;</span>
            <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token number">0.92</span>rem<span class="token punctuation">;</span>
            <span class="token property">text-transform</span><span class="token punctuation">:</span> uppercase<span class="token punctuation">;</span>
            <span class="token property">letter-spacing</span><span class="token punctuation">:</span> <span class="token number">0.08</span>em<span class="token punctuation">;</span>
            <span class="token property">color</span><span class="token punctuation">:</span> <span class="token hexcode">#e5e7eb</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.badge</span> </span><span class="token punctuation">{</span>
        <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token hexcode">#333333</span><span class="token punctuation">;</span>
        <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text-main<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token number">2</span>px <span class="token number">9</span>px<span class="token punctuation">;</span>
        <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token number">999</span>px<span class="token punctuation">;</span>
        <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token number">0.74</span>rem<span class="token punctuation">;</span>
        <span class="token property">font-weight</span><span class="token punctuation">:</span> <span class="token number">600</span><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 function">var</span><span class="token punctuation">(</span>--border-glass<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">box-shadow</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.coupon-grid</span> </span><span class="token punctuation">{</span>
        <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
        <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span><span class="token number">2</span>, <span class="token function">minmax</span><span class="token punctuation">(</span><span class="token number">0</span>, <span class="token number">1</span>fr<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token number">14</span>px<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.course-item</span> </span><span class="token punctuation">{</span>
        <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token number">10</span>px <span class="token number">12</span>px <span class="token number">8</span>px<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">flex-direction</span><span class="token punctuation">:</span> column<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">.course-info</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">justify-content</span><span class="token punctuation">:</span> space-between<span class="token punctuation">;</span>
        <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
        <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token number">10</span>px<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.course-name</span> </span><span class="token punctuation">{</span>
        <span class="token property">font-weight</span><span class="token punctuation">:</span> <span class="token number">600</span><span class="token punctuation">;</span>
        <span class="token property">color</span><span class="token punctuation">:</span> <span class="token hexcode">#2d2d30</span><span class="token punctuation">;</span>
        <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token number">0.95</span>rem<span class="token punctuation">;</span>
        <span class="token property">white-space</span><span class="token punctuation">:</span> nowrap<span class="token punctuation">;</span>
        <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span>
        <span class="token property">text-overflow</span><span class="token punctuation">:</span> ellipsis<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.course-price</span> </span><span class="token punctuation">{</span>
        <span class="token property">font-weight</span><span class="token punctuation">:</span> <span class="token number">600</span><span class="token punctuation">;</span>
        <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--accent-green<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token number">0.86</span>rem<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token class">.course-category</span> </span><span class="token punctuation">{</span>
        <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token number">0.8</span>rem<span class="token punctuation">;</span>
        <span class="token property">color</span><span class="token punctuation">:</span> <span class="token hexcode">#6e6e6e</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token pseudo-class">:deep(.k-listbox)</span> </span><span class="token punctuation">{</span>
        <span class="token property">border</span><span class="token punctuation">:</span> none <span class="token important">!important</span><span class="token punctuation">;</span>
        <span class="token property">background</span><span class="token punctuation">:</span> transparent<span class="token punctuation">;</span>
        <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text-main<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token pseudo-class">:deep(.k-listbox .k-list-content)</span> </span><span class="token punctuation">{</span>
        <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--radius-md<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token number">8</span>px<span class="token punctuation">;</span>
        <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token hexcode">#1e1e1e</span><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 function">var</span><span class="token punctuation">(</span>--border-glass<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token pseudo-class">:deep(.k-listbox .k-list-item)</span> </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 property">margin</span><span class="token punctuation">:</span> <span class="token number">2</span>px <span class="token number">3</span>px<span class="token punctuation">;</span>
        <span class="token property">transition</span><span class="token punctuation">:</span> background-color <span class="token function">var</span><span class="token punctuation">(</span>--transition-fast<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text-main<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token pseudo-class">:deep(.k-listbox .k-list-item:hover)</span> </span><span class="token punctuation">{</span>
        <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token hexcode">#2d2d30</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token pseudo-class">:deep(.k-listbox .k-list-item.k-selected)</span> </span><span class="token punctuation">{</span>
        <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--accent-blue<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">color</span><span class="token punctuation">:</span> <span class="token hexcode">#1e1e1e</span><span class="token punctuation">;</span>
        <span class="token property">box-shadow</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector"><span class="token pseudo-class">:deep(.k-listbox .k-list-item.k-selected .course-name)</span>,
    <span class="token pseudo-class">:deep(.k-listbox .k-list-item.k-selected .course-price)</span>,
    <span class="token pseudo-class">:deep(.k-listbox .k-list-item.k-selected .course-category)</span> </span><span class="token punctuation">{</span>
        <span class="token property">color</span><span class="token punctuation">:</span> <span class="token hexcode">#1e1e1e</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    @<span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">max-width</span><span class="token punctuation">:</span> 1200px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
        <span class="token selector"><span class="token class">.lists-container</span> </span><span class="token punctuation">{</span>
            <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">minmax</span><span class="token punctuation">(</span><span class="token number">0</span>, <span class="token number">1</span>fr<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token selector"><span class="token class">.coupon-grid</span> </span><span class="token punctuation">{</span>
            <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span><span class="token number">2</span>, <span class="token function">minmax</span><span class="token punctuation">(</span><span class="token number">0</span>, <span class="token number">1</span>fr<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 atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">max-width</span><span class="token punctuation">:</span> 768px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
        <span class="token selector"><span class="token class">.demo-container</span> </span><span class="token punctuation">{</span>
            <span class="token property">padding-inline</span><span class="token punctuation">:</span> <span class="token number">14</span>px<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token selector"><span class="token class">.lists-container</span> </span><span class="token punctuation">{</span>
            <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">minmax</span><span class="token punctuation">(</span><span class="token number">0</span>, <span class="token number">1</span>fr<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token number">14</span>px<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token selector"><span class="token class">.coupon-grid</span> </span><span class="token punctuation">{</span>
            <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">minmax</span><span class="token punctuation">(</span><span class="token number">0</span>, <span class="token number">1</span>fr<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">&gt;</span></span>

@code {
    public class Course
    {
        public int Id { get; set; }
        public string Name { get; set; } = string.Empty;
        public string Category { get; set; } = string.Empty;
        public decimal Price { get; set; }
        public string Currency { get; set; } = "USD";
    }

    private List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span> AvailableCourses { get; set; } = new();
    private List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span> BestPriceCourses { get; set; } = new();
    private List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span> CustomPriceCourses { get; set; } = new();
    private List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span> FreeOpenCourses { get; set; } = new();
    private List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span> FreeTargetedCourses { get; set; } = new();

    protected override void OnInitialized()
    {
        LoadSampleData();
    }

    private void LoadSampleData()
    {
        AvailableCourses = new List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span>
        {
            new() { Id = 1, Name = "Blazor Fundamentals", Category = "Web Development", Price = 19.99m, Currency = "USD" },
            new() { Id = 2, Name = "C# Advanced Patterns", Category = "Programming", Price = 24.99m, Currency = "USD" },
            new() { Id = 3, Name = "ASP.NET Core API", Category = "Backend", Price = 29.99m, Currency = "USD" },
            new() { Id = 4, Name = "Entity Framework Core", Category = "Database", Price = 14.99m, Currency = "USD" },
            new() { Id = 5, Name = "Azure DevOps Pipeline", Category = "DevOps", Price = 34.99m, Currency = "USD" },
            new() { Id = 6, Name = "Docker &amp; Kubernetes", Category = "Infrastructure", Price = 39.99m, Currency = "USD" },
            new() { Id = 7, Name = "React with TypeScript", Category = "Frontend", Price = 22.99m, Currency = "USD" },
            new() { Id = 8, Name = "SQL Server Mastery", Category = "Database", Price = 27.99m, Currency = "USD" },
            new() { Id = 9, Name = "Git &amp; GitHub Pro", Category = "Tools", Price = 12.99m, Currency = "USD" },
            new() { Id = 10, Name = "Machine Learning Basics", Category = "AI/ML", Price = 44.99m, Currency = "USD" }
        };
        BestPriceCourses = new();
        CustomPriceCourses = new();
        FreeOpenCourses = new();
        FreeTargetedCourses = new();
    }
}
</code></pre><p>In the code above, you can see that we used several <code>TelerikListBox</code> tags to render the ListBox components, as well as the use of <code>ItemTemplate</code> to apply styles to each item within the ListBox.</p><p>Similarly, I have created a class <code>Course</code> that represents a course, which is useful for filling and binding the lists to each ListBox through the <code>Data</code> parameter of the component to display the information, as shown below:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/page-displaying-listboxes-for-blazor-that-will-be-used-to-transfer-items-between-them.png?sfvrsn=969c108b_2" alt="Page displaying ListBoxes for Blazor that will be used to transfer items between them" /></p><p>The result is fascinating and undoubtedly demonstrates the potential of the component.</p><h2 id="enabling-drag--drop-functionality">Enabling Drag &amp; Drop Functionality</h2><p>The <code>TelerikListBox</code> component has several parameters that we need to configure so that we can drag and drop items between ListBoxes, following these steps. It is worth mentioning that I will show you the configuration for just one, although the implementation for the others is similar.</p><ol><li>Each of the ListBoxes that will be used to transfer items must have an id of type <code>string</code>, which should be set in the <code>Id</code> parameter. This is essential for knowing from which component the item is coming and where it is going. An example of this configuration is shown below:</li></ol><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikListBox</span> <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@AvailableCourses<span class="token punctuation">"</span></span>
                <span class="token attr-name">Id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ListBoxIdAvailable<span class="token punctuation">"</span></span>
                <span class="token attr-name">...</span><span class="token punctuation">&gt;</span></span>
    ...
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikListBox</span><span class="token punctuation">&gt;</span></span>
@code {
    ...
    private const string ListBoxIdAvailable = "availableCourses";
    ...
}
</code></pre><ol start="2"><li>The second step is to create <code>@ref</code> references, which allows invoking the <code>Rebind</code> method to carry out a data update every time we move items between the lists:</li></ol><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikListBox</span> <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@AvailableCourses<span class="token punctuation">"</span></span>
                <span class="token attr-name">@ref</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ListBoxRefAvailable<span class="token punctuation">"</span></span>
                <span class="token attr-name">...</span><span class="token punctuation">&gt;</span></span>
    ...
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikListBox</span><span class="token punctuation">&gt;</span></span>
@code {
    ...
    private TelerikListBox<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span> ListBoxRefAvailable { get; set; } = null!;
    ...
}
</code></pre><ol start="3"><li>You must be able to obtain the selected elements from each ListBox, which is possible by creating a list for each ListBox and binding them through the <code>SelectedItems</code> property. Also, make sure to specify the appropriate <code>SelectionMode</code> type, as well as assign the <code>SelectedItemsChanged</code> parameter to update these lists:</li></ol><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikListBox</span> <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@AvailableCourses<span class="token punctuation">"</span></span>
                <span class="token attr-name">SelectionMode</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ListBoxSelectionMode.Multiple<span class="token punctuation">"</span></span>
                <span class="token attr-name">SelectedItems</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@SelectedItemsAvailable<span class="token punctuation">"</span></span>
                <span class="token attr-name">SelectedItemsChanged</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@((IEnumerable&lt;Course&gt; items) =&gt; OnSelectedItemsChanged(items, ListBoxIdAvailable))<span class="token punctuation">"</span></span>
                <span class="token attr-name">...</span><span class="token punctuation">&gt;</span></span>
    ...
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikListBox</span><span class="token punctuation">&gt;</span></span>
@code {
    ...
    private IEnumerable<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span> SelectedItemsAvailable { get; set; } = new List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span>();
    private IEnumerable<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span> SelectedItems1 { get; set; } = new List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span>();
    private IEnumerable<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span> SelectedItems2 { get; set; } = new List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span>();
    private IEnumerable<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span> SelectedItems3 { get; set; } = new List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span>();
    private IEnumerable<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span> SelectedItems4 { get; set; } = new List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span>();
    ...
    private void OnSelectedItemsChanged(IEnumerable<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Course</span><span class="token punctuation">&gt;</span></span> items, string listBoxId)
    {
        switch (listBoxId)
        {
            case ListBoxIdAvailable:
                SelectedItemsAvailable = items;
                break;
            case ListBoxId1:
                SelectedItems1 = items;
                break;
            case ListBoxId2:
                SelectedItems2 = items;
                break;
            case ListBoxId3:
                SelectedItems3 = items;
                break;
            case ListBoxId4:
                SelectedItems4 = items;
                break;
        }
    }        
    ...
}
</code></pre><ol start="4"><li>You must assign a <code>true</code> value to the <code>Draggable</code> parameter, indicating that the ListBoxes will be able to send and receive items between them.</li></ol><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikListBox</span> <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@AvailableCourses<span class="token punctuation">"</span></span>
                <span class="token attr-name">Draggable</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">...</span><span class="token punctuation">&gt;</span></span>
    ...
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikListBox</span><span class="token punctuation">&gt;</span></span>
</code></pre><ol start="5"><li>Enable the <code>DropSources</code> parameter, which is a list of Ids of the ListBoxes.</li></ol><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikListBox</span> <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@AvailableCourses<span class="token punctuation">"</span></span>
                <span class="token attr-name">DropSources</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@ListBoxDropSources<span class="token punctuation">"</span></span>
                <span class="token attr-name">...</span><span class="token punctuation">&gt;</span></span>
    ...
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikListBox</span><span class="token punctuation">&gt;</span></span>
@code {
    ...
    private List<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">&gt;</span></span> ListBoxDropSources =&gt; new()
    {
        ListBoxIdAvailable,
        ListBoxId1,
        ListBoxId2,
        ListBoxId3,
        ListBoxId4
    };
    ...
}
</code></pre><ol start="6"><li>Specify the <code>OnDrop</code> parameter, which is an <code>EventCallback</code> that is triggered when a drag-and-drop interaction occurs, expecting a delegate that receives an argument <code>ListBoxDropEventArgs&lt;T&gt;</code>. This argument contains a property <code>Items</code> with the elements being moved between ListBoxes, a <code>DestinationIndex</code> that represents the index within the destination ListBox where the item was dropped, and finally <code>DestinationListBoxId</code>, which allows knowing in which ListBox we dropped the items. Additionally, we can add information like the <code>Id</code> of the ListBox from which the operation is being performed:</li></ol><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TelerikListBox</span> <span class="token attr-name">Data</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@AvailableCourses<span class="token punctuation">"</span></span>
                <span class="token attr-name">OnDrop</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@((ListBoxDropEventArgs&lt;Course&gt; args) =&gt; OnDropHandler(args, ListBoxIdAvailable))<span class="token punctuation">"</span></span>
                <span class="token attr-name">...</span><span class="token punctuation">&gt;</span></span>
    ...
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>TelerikListBox</span><span class="token punctuation">&gt;</span></span>
</code></pre><ol start="7"><li>Create the event handler where the processing takes place when the items are dropped. This method is the most complex, but I will explain the main parts:</li></ol><pre class=" language-csharp"><code class="prism  language-csharp">@code <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 keyword">void</span> <span class="token function">OnDropHandler</span><span class="token punctuation">(</span>ListBoxDropEventArgs<span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span> args<span class="token punctuation">,</span> <span class="token keyword">string</span> sourceListBoxId<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token comment">// A. </span>
        <span class="token keyword">var</span> draggedItem <span class="token operator">=</span> args<span class="token punctuation">.</span>Items<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">FirstOrDefault</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>draggedItem <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>                    
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>sourceListBoxId<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">var</span> destinationId <span class="token operator">=</span> args<span class="token punctuation">.</span>DestinationListBoxId<span class="token punctuation">;</span>
        <span class="token keyword">var</span> destinationIndex <span class="token operator">=</span> args<span class="token punctuation">.</span>DestinationIndex <span class="token operator">?</span><span class="token operator">?</span> <span class="token number">0</span><span class="token punctuation">;</span>        
        <span class="token keyword">var</span> sourceList <span class="token operator">=</span> <span class="token function">GetListById</span><span class="token punctuation">(</span>sourceListBoxId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">var</span> destinationList <span class="token operator">=</span> <span class="token function">GetListById</span><span class="token punctuation">(</span>destinationId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>sourceList <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> destinationList <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>        
        <span class="token keyword">var</span> selectedItems <span class="token operator">=</span> <span class="token function">GetSelectedItemsFromListBox</span><span class="token punctuation">(</span>sourceListBoxId<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// B.</span>
        List<span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span> itemsToMove<span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>selectedItems<span class="token punctuation">.</span><span class="token function">Any</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> selectedItems<span class="token punctuation">.</span><span class="token function">Any</span><span class="token punctuation">(</span>item <span class="token operator">=</span><span class="token operator">&gt;</span> item<span class="token punctuation">.</span>Id <span class="token operator">==</span> draggedItem<span class="token punctuation">.</span>Id<span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            itemsToMove <span class="token operator">=</span> selectedItems<span class="token punctuation">.</span><span class="token function">ToList</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">else</span>
        <span class="token punctuation">{</span>
            itemsToMove <span class="token operator">=</span> args<span class="token punctuation">.</span>Items<span class="token punctuation">.</span><span class="token function">ToList</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">// C. </span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>destinationId <span class="token operator">==</span> sourceListBoxId<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>            
            <span class="token function">ReorderItems</span><span class="token punctuation">(</span>itemsToMove<span class="token punctuation">,</span> sourceList<span class="token punctuation">,</span> destinationIndex<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">else</span>
        <span class="token punctuation">{</span>            
            <span class="token function">MoveItems</span><span class="token punctuation">(</span>itemsToMove<span class="token punctuation">,</span> sourceList<span class="token punctuation">,</span> destinationList<span class="token punctuation">,</span> destinationIndex<span class="token punctuation">)</span><span class="token punctuation">;</span>            
            <span class="token function">ClearSelectedItems</span><span class="token punctuation">(</span>sourceListBoxId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        
        <span class="token function">RebindAllListBoxes</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>A. The variables <code>draggedItem</code>, <code>destinationId</code>, <code>destinationIndex</code>, <code>sourceList</code>, <code>destinationList</code> and <code>selectedItems</code> are created, which will serve to perform different operations such as validations, reordering, etc.</p><p>B. The variable <code>itemsToMove</code> is created, which will establish which items will be moved. The check allows specifying which items will be moved, whether the selected ones or some different ones. For example, suppose you select the first two items, and for some reason, you prefer not to move them, but instead, you prefer to move Item 3. In this case, only Item 3 will be moved and not the selected ones.</p><p>C. The <code>if</code> allows knowing if the movement of items has been made within the same list or if an attempt is being made to move between different lists. If it is within the same list, reordering is done according to the <code>destinationIndex</code>. If the transfer is made between lists, the items are moved between the lists and deselected. Finally, a <code>Rebind</code> is carried out to update any pending interface changes.</p><p>Lastly, I show you the helper methods used:</p><pre class=" language-csharp"><code class="prism  language-csharp">@code <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> List<span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span><span class="token operator">?</span> <span class="token function">GetListById</span><span class="token punctuation">(</span><span class="token keyword">string</span> listBoxId<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">return</span> listBoxId <span class="token keyword">switch</span>
        <span class="token punctuation">{</span>
            ListBoxIdAvailable <span class="token operator">=</span><span class="token operator">&gt;</span> AvailableCourses<span class="token punctuation">,</span>
            ListBoxId1 <span class="token operator">=</span><span class="token operator">&gt;</span> BestPriceCourses<span class="token punctuation">,</span>
            ListBoxId2 <span class="token operator">=</span><span class="token operator">&gt;</span> CustomPriceCourses<span class="token punctuation">,</span>
            ListBoxId3 <span class="token operator">=</span><span class="token operator">&gt;</span> FreeOpenCourses<span class="token punctuation">,</span>
            ListBoxId4 <span class="token operator">=</span><span class="token operator">&gt;</span> FreeTargetedCourses<span class="token punctuation">,</span>
            _ <span class="token operator">=</span><span class="token operator">&gt;</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 keyword">private</span> IEnumerable<span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span> <span class="token function">GetSelectedItemsFromListBox</span><span class="token punctuation">(</span><span class="token keyword">string</span> listBoxId<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">return</span> listBoxId <span class="token keyword">switch</span>
        <span class="token punctuation">{</span>
            ListBoxIdAvailable <span class="token operator">=</span><span class="token operator">&gt;</span> SelectedItemsAvailable <span class="token operator">?</span><span class="token operator">?</span> <span class="token keyword">new</span> <span class="token class-name">List</span><span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            ListBoxId1 <span class="token operator">=</span><span class="token operator">&gt;</span> SelectedItems1 <span class="token operator">?</span><span class="token operator">?</span> <span class="token keyword">new</span> <span class="token class-name">List</span><span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            ListBoxId2 <span class="token operator">=</span><span class="token operator">&gt;</span> SelectedItems2 <span class="token operator">?</span><span class="token operator">?</span> <span class="token keyword">new</span> <span class="token class-name">List</span><span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            ListBoxId3 <span class="token operator">=</span><span class="token operator">&gt;</span> SelectedItems3 <span class="token operator">?</span><span class="token operator">?</span> <span class="token keyword">new</span> <span class="token class-name">List</span><span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            ListBoxId4 <span class="token operator">=</span><span class="token operator">&gt;</span> SelectedItems4 <span class="token operator">?</span><span class="token operator">?</span> <span class="token keyword">new</span> <span class="token class-name">List</span><span class="token operator">&lt;</span>Course<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">=</span><span class="token operator">&gt;</span> <span class="token keyword">new</span> <span class="token class-name">List</span><span class="token operator">&lt;</span>Course<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 keyword">private</span> <span class="token keyword">void</span> <span class="token function">ReorderItems</span><span class="token punctuation">(</span>List<span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span> items<span class="token punctuation">,</span> List<span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span> collection<span class="token punctuation">,</span> <span class="token keyword">int</span> destinationIndex<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>        
        <span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token keyword">var</span> item <span class="token keyword">in</span> items<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            collection<span class="token punctuation">.</span><span class="token function">RemoveAll</span><span class="token punctuation">(</span>x <span class="token operator">=</span><span class="token operator">&gt;</span> x<span class="token punctuation">.</span>Id <span class="token operator">==</span> item<span class="token punctuation">.</span>Id<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>destinationIndex <span class="token operator">&gt;=</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> destinationIndex <span class="token operator">&lt;=</span> collection<span class="token punctuation">.</span>Count<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">var</span> index <span class="token operator">=</span> destinationIndex<span class="token punctuation">;</span>
            <span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token keyword">var</span> item <span class="token keyword">in</span> items<span class="token punctuation">)</span>
            <span class="token punctuation">{</span>
                collection<span class="token punctuation">.</span><span class="token function">Insert</span><span class="token punctuation">(</span>index<span class="token punctuation">,</span> item<span class="token punctuation">)</span><span class="token punctuation">;</span>
                index<span class="token operator">++</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">else</span>
        <span class="token punctuation">{</span>
            collection<span class="token punctuation">.</span><span class="token function">AddRange</span><span class="token punctuation">(</span>items<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 keyword">void</span> <span class="token function">MoveItems</span><span class="token punctuation">(</span>List<span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span> items<span class="token punctuation">,</span> List<span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span> sourceList<span class="token punctuation">,</span> List<span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span> destinationList<span class="token punctuation">,</span> <span class="token keyword">int</span> destinationIndex<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>        
        <span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token keyword">var</span> item <span class="token keyword">in</span> items<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            sourceList<span class="token punctuation">.</span><span class="token function">RemoveAll</span><span class="token punctuation">(</span>x <span class="token operator">=</span><span class="token operator">&gt;</span> x<span class="token punctuation">.</span>Id <span class="token operator">==</span> item<span class="token punctuation">.</span>Id<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        
        <span class="token keyword">var</span> insertIndex <span class="token operator">=</span> destinationIndex <span class="token operator">&gt;=</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> destinationIndex <span class="token operator">&lt;=</span> destinationList<span class="token punctuation">.</span>Count
            <span class="token operator">?</span> destinationIndex
            <span class="token punctuation">:</span> destinationList<span class="token punctuation">.</span>Count<span class="token punctuation">;</span>

        <span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token keyword">var</span> item <span class="token keyword">in</span> items<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            destinationList<span class="token punctuation">.</span><span class="token function">Insert</span><span class="token punctuation">(</span>insertIndex<span class="token punctuation">,</span> item<span class="token punctuation">)</span><span class="token punctuation">;</span>
            insertIndex<span class="token operator">++</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 keyword">void</span> <span class="token function">ClearSelectedItems</span><span class="token punctuation">(</span><span class="token keyword">string</span> listBoxId<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">switch</span> <span class="token punctuation">(</span>listBoxId<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">case</span> ListBoxIdAvailable<span class="token punctuation">:</span>
                SelectedItemsAvailable <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">List</span><span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">break</span><span class="token punctuation">;</span>
            <span class="token keyword">case</span> ListBoxId1<span class="token punctuation">:</span>
                SelectedItems1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">List</span><span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">break</span><span class="token punctuation">;</span>
            <span class="token keyword">case</span> ListBoxId2<span class="token punctuation">:</span>
                SelectedItems2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">List</span><span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">break</span><span class="token punctuation">;</span>
            <span class="token keyword">case</span> ListBoxId3<span class="token punctuation">:</span>
                SelectedItems3 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">List</span><span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">break</span><span class="token punctuation">;</span>
            <span class="token keyword">case</span> ListBoxId4<span class="token punctuation">:</span>
                SelectedItems4 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">List</span><span class="token operator">&lt;</span>Course<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">break</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 keyword">void</span> <span class="token function">RebindAllListBoxes</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        ListBoxRefAvailable<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">Rebind</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        ListBoxRef1<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">Rebind</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        ListBoxRef2<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">Rebind</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        ListBoxRef3<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">Rebind</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        ListBoxRef4<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">Rebind</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>With the above code implemented, we now have drag and drop on the page, working with both individual elements and multiple elements as shown below:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/demonstration-of-drag-and-drop-functionality-across-multiple-listboxes-in-blazor.gif?sfvrsn=6ca54571_2" alt="Demonstration of drag-and-drop functionality across multiple ListBoxes in Blazor" /></p><p>With this, we have finished implementing the drag-and-drop functionality. Finally, we could obtain the list of courses in each of the bound lists in the ListBoxes to get their classification, thus generating a final CSV file to create coupons in bulk easily, which greatly simplifies coupon generation.</p><h2 id="conclusion">Conclusion</h2><p>The creation of applications should always be oriented toward enabling users to solve their problems without worrying about performing complex steps.</p><p>In this article, we have seen how to solve a real-world problem through the implementation of drag and drop using the <code>TelerikListBox</code> component. You have learned the steps involved in enabling it and some methods that can help you carry out this implementation more easily. I hope this is very helpful to you and that at some point you can implement it to assist your users.</p><p>Ready to try out this component and 120 others in the Telerik UI for Blazor library? The trial is free for 30 days!</p><p><a href="https://www.telerik.com/try/ui-for-blazor" target="_blank" class="Btn">Try Now</a></p><img src="https://feeds.telerik.com/link/23050/17277349.gif" height="1" width="1"/>]]></content>
  </entry>
</feed>
