<?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>
  <feedpress:newsletterId>telerik-blogs-web</feedpress:newsletterId>
  <link rel="hub" href="https://feedpress.superfeedr.com/"/>
  <logo>https://static.feedpress.com/logo/telerik-blogs--web-5ab52bef0a72f.jpg</logo>
  <title type="text">Telerik Blogs | Web</title>
  <subtitle type="text">The official blog of Progress Telerik - expert articles and tutorials for developers.</subtitle>
  <id>uuid:c19a6334-6895-4209-91d2-39f4e81dcd0d;id=2363</id>
  <updated>2026-04-18T12:15:37Z</updated>
  <link rel="alternate" href="https://www.telerik.com/"/>
  <link rel="self" type="application/atom+xml" href="https://feeds.telerik.com/blogs/web"/>
  <entry>
    <id>urn:uuid:f462deac-a01d-48d3-9fca-87eea0bb03f4</id>
    <title type="text">The 10 Best Angular UI Libraries</title>
    <summary type="text">TL;DR What’s the best Angular UI library? If you’re looking for build speed thanks to robust components, AI capabilities, built-in design options and a ready support community, the Progress Kendo UI for Angular library is hard to beat.</summary>
    <published>2026-04-16T14:51:07Z</published>
    <updated>2026-04-18T12:15:37Z</updated>
    <author>
      <name>Dany Paredes </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17320248/10-best-angular-ui-libraries"/>
    <content type="text"><![CDATA[<p><span class="featured"><strong>TL;DR What&rsquo;s the best Angular UI library?</strong> If you&rsquo;re looking for build speed thanks to robust components, AI capabilities, built-in design options and a ready support community, the Progress Kendo UI for Angular library is hard to beat.</span></p><p>I&rsquo;ve been developing software for more than 15 years, and the industry never stops changing. Choosing a framework is a strategic decision that must fit the time we are building in.</p><p>Building apps in 2026 is very different from 2015, 2020 or even 2025. Today, picking a UI library is more complex than before. We are no longer just building simple &ldquo;forms and tables&rdquo;; we are building AI-powered experiences. As developers, we now work with AI agents like Cursor and Copilot, and our UI library must be ready for AI from day one.</p><p>The best Angular library does not just save time with CSS or provide basic typical components; it must provide components and tools to help AI and agents understand our code better, saving tokens, time and money for your company, and also help the entire team to work better.</p><p>But as always, the best way to explain the importance of this choice is to look at a real-world situation.</p><h2 id="the-scenario">The Scenario</h2><p>Imagine you were just hired by a startup. You must deliver a complex platform quickly to compete in the market, but your app is modern in the AI era, so it needs more than basic grids and buttons. It will also have complex calendars, real-time charts, chat interfaces and anything needed to perform in accordance with modern user expectations &hellip; and it needs to help our new teammates (AI coding agents) work better and faster.</p><p>In this situation, your UI library is not just about delivering on time. It is about providing a tool that can help you ship your project, support your team with very stable code and provide complex features so you don&rsquo;t have to build everything from zero. You need a library that is already &ldquo;AI-ready,&rdquo; with components made for AI agents and chat interfaces.</p><blockquote><p>I can tell you, from experience, picking the wrong library can mean months of extra work and watching your competitors launch while you are still fixing basic things.</p></blockquote><p>Today, we are going to dive into each framework, showing its strengths and weaknesses, and finally my recommendation for each scenario.</p><h2 id="kendo-ui-for-angular">1. Kendo UI for Angular</h2><p>In the scenario we described, the Progress <a target="_blank" href="https://www.telerik.com/kendo-angular-ui">Kendo UI for Angular</a> component library is your best all-in-one framework. When the deadline is close and the project is high-priority, you do not have time to build everything from scratch.</p><h3 id="why-kendo-ui-is-the-best-tool-for-projects">Why Kendo UI Is the Best Tool for Projects</h3><ul><li><p><strong>Built for speed:</strong> With <strong><a target="_blank" href="https://www.telerik.com/kendo-angular-ui#components">120+ components</a></strong> (Grid, Excel, Charts, Scheduler, etc.) and ready-to-use <a target="_blank" href="https://www.telerik.com/page-templates-and-ui-blocks"><strong>Page Templates</strong></a>, you will be assembling your app quickly. You can save <em>weeks</em> of work and focus on the important parts of your code while an entire team at Progress manages the upkeep of your component library.</p></li><li><p><strong><a target="_blank" href="https://www.telerik.com/mcp-servers">MCP Server</a>:</strong> Kendo UI is an AI-ready framework for developers and agents to increase productivity. Today, every hour (and token) is valuable. The Kendo UI MCP Server helps your AI agents (like VS Code or Cursor) write better code by following Kendo UI best practices that come directly from the team that built the software, reducing hallucinations and allowing your developers and agents ship code fast yet with the highest quality.</p></li><li><p><strong><a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-components">AI-ready Angular components</a>:</strong> Add intelligent features quickly with components like AIPrompt, SmartPaste or AI features in the Grid. This makes your app look modern with very little effort.</p></li><li><p><strong><a target="_blank" href="https://themebuilder.telerik.com/">ThemeBuilder</a>:</strong> Avoid wasting time on CSS. You can import design tokens from Figma and get your style right the first time without writing thousands of lines of code.</p></li><li><p><strong><a target="_blank" href="https://www.telerik.com/purchase/support-plans">Expert help:</a></strong> The tier-based support plans give you peace of mind. If you have a problem at a critical moment, you have a team of professional engineers to help you, not just a public forum (but the community support is also robust!).</p></li></ul><p><strong>Pro tip:</strong> You can <a target="_blank" href="https://www.telerik.com/try/kendo-angular-ui">try Kendo UI for Angular completely free</a> for 30 days, <strong>no credit card required</strong>. It&rsquo;s the fastest way to prove to your team that you can meet that &ldquo;impossible&rdquo; deadline.</p><p>But what if you are looking for Google&rsquo;s official baseline? That brings us to our next pick.</p><h2 id="angular-material">2. Angular Material</h2><p><a target="_blank" href="https://material.angular.io/">Angular Material</a> is the official UI suite maintained by the Angular team. It implements Google&rsquo;s Material Design and is often the first choice for developers looking for a standard, predictable foundation. While it&rsquo;s the community baseline, in 2026, many projects find its rigid structure a limiting factor.</p><p>If you&rsquo;ve ever worked in an Angular project, you&rsquo;ve probably used it. It&rsquo;s the industry standard for a reason, but standards aren&rsquo;t always enough for every project.</p><ul><li><p><strong>The Good:</strong> It is very stable. Because it is built by the same team that makes Angular, it always works with the latest versions. It follows Google&rsquo;s Material Design and looks clean and professional.</p></li><li><p><strong>The Cons:</strong> The customization is difficult. If you need a unique look for your brand, you will spend a lot of time fighting with CSS. It also lacks advanced components for big data, like high-performance Grids or Calendars.</p></li><li><p><strong>My Feedback:</strong> I have seen many teams spend weeks trying to make Material look different. Also, Material lacks complex tools like a <strong>Scheduler</strong> or a <strong>Gantt Chart</strong>. If your project needs more than just basic forms, I recommend <strong>Kendo UI</strong>. It gives you 120+ advanced parts that are ready for big business needs, saving you the work of building them yourself.</p></li></ul><p>If Material feels too rigid and you need a massive variety of &ldquo;out-of-the-box&rdquo; gadgets, you might want to consider our next option.</p><h2 id="primeng">3. PrimeNG</h2><p><a target="_blank" href="https://primeng.org/">PrimeNG</a> is one of the well-known libraries in the ecosystem with a collection of components. While its catalog is extensive, navigating its many options can require a significant investment in terms of styling and consistency in larger apps.</p><ul><li><p><strong>The Good:</strong> Their variety is unmatched. PrimeNG has many components from simple buttons to complex organization charts.</p></li><li><p><strong>The Cons:</strong> Maintaining a perfectly consistent visual style across many complex components can become tricky in large-scale projects. The styling system can sometimes feel overwhelming when you need deep, unified brand customization.</p></li><li><p><strong>My Feedback:</strong> Kendo UI provides more than just a framework. It offers tools like ThemeBuilder, Figma kits, MCP tools and AI-ready components to provide a smooth developer experience.</p></li></ul><p>Now, if your project is heavily focused on data and complex dashboards, check out the next player in the game.</p><h2 id="syncfusion-angular">4. Syncfusion Angular</h2><p><a target="_blank" href="https://www.syncfusion.com/angular-ui-components">Syncfusion</a> is an enterprise-focused suite that offers a wide range of specialized components.</p><ul><li><p><strong>The Good:</strong> Their charts and grids are powerful. They are a good choice for data-heavy applications and dashboards.</p></li><li><p><strong>The Cons:</strong> The API does not always feel like standard Angular, which makes it harder to learn. It is also difficult to customize the components to match a Figma design. This is a framework built for developers, but real-world projects need to include the whole team.</p></li><li><p><strong>My Feedback:</strong> We should not waste time manually syncing Figma styles with components. I prefer Kendo UI because it is designed for developers, designers and AI agents. This provides a smooth experience for everyone on the team.</p></li></ul><p>Speaking of data apps, sometimes you don&rsquo;t need a full suite. If your app is 90% tables, then you should take a look at the next one.</p><h2 id="ag-grid">5. AG Grid</h2><p><a target="_blank" href="https://www.ag-grid.com/angular-data-grid/">AG Grid</a> is a specialized library almost entirely focused on data grids. It&rsquo;s a common choice for applications where tabular data is the main focus, though it requires pairing with other libraries for common UI elements like buttons and modals.</p><ul><li><p><strong>The Good:</strong> If your application is 90% tables, this is a great choice. Its performance with very large datasets is good.</p></li><li><p><strong>The Cons:</strong> The real world is not only a grid. You will still need to find and style other libraries to solve other scenarios in your app, often resulting in a UI with inconsistent styles that is hard to maintain.</p></li><li><p><strong>My Feedback:</strong> AG Grid is powerful, but it is only one part of what you&rsquo;ll need. Kendo UI gives you that same grid power in a <strong>unified system</strong>. This means your Grid, Buttons and Charts all share the same style and logic. Plus, Kendo UI has built-in <strong>PDF and Excel exporting</strong> that works perfectly without extra work.</p></li></ul><p>But what if you need that speed in more than just tables? Let&rsquo;s see the next option.</p><h2 id="ignite-ui-for-angular">6. Ignite UI for Angular</h2><p><a target="_blank" href="https://www.infragistics.com/products/ignite-ui-angular">Ignite UI for Angular</a> is focused on data visualization and performance. It&rsquo;s often used in scenarios where real-time charts are a priority, though its ecosystem is smaller than other major players.</p><ul><li><p><strong>The Good:</strong> Great charts and a very fast rendering engine, especially for real-time data.</p></li><li><p><strong>The Cons:</strong> The ecosystem and community are smaller than the large libraries on this list. This can make it harder to find help for specific problems. Also, similar to AG Grid, in the real world our apps are more than a dashboard. They work with a combination of features that take time to build by yourself.</p></li><li><p><strong>My Feedback:</strong> Unlike Ignite UI, Kendo UI has Building Blocks that can solve common scenarios like login, register, forgot password, etc. Kendo UI has a very large community and <strong>professional support</strong>. This means you can always get help when you are stuck, making it a safer choice for important projects.</p></li></ul><p>If you&rsquo;re already familiar with the DevExpress environment from other platforms, then you&rsquo;ll feel right at home with our next pick.</p><h2 id="devextreme-angular">7. DevExtreme Angular</h2><p><a target="_blank" href="https://js.devexpress.com/Angular/">DevExtreme Angular</a> by DevExpress has its roots in traditional software development, carrying over patterns from WinForms and ASP.NET. This makes it a familiar choice for teams coming from a more classical enterprise background, though its developer experience can feel a bit dated for modern web standards.</p><ul><li><p><strong>The Good:</strong> Perfect for developers who already use DevExpress and need complex reporting tools and traditional business components.</p></li><li><p><strong>The Cons:</strong> It can feel a bit &ldquo;old&rdquo; in terms of how you write code. Changing the CSS to meet modern web standards is often a difficult and long task.</p></li><li><p><strong>My Feedback:</strong> To avoid the old code patterns of DevExtreme, Kendo UI offers a clean, <strong>modern architecture</strong>. It helps you build fast without creating messy code that is hard to fix later.</p></li></ul><p>For those who prefer a clean, minimal design system like Ant Design, there&rsquo;s a popular community implementation you should know about.</p><h2 id="ng-zorro">8. NG-ZORRO</h2><p><a target="_blank" href="https://ng.ant.design/">NG-ZORRO</a> is a community-driven implementation of the Ant Design system for Angular. It&rsquo;s aimed at developers who want a ready-made aesthetic for dashboards. However, its community-based nature means it lacks the dedicated professional support found in commercial suites.</p><ul><li><p><strong>The Good:</strong> It creates beautiful and professional-looking interfaces immediately. Excellent for internal tools where speed is important.</p></li><li><p><strong>The Cons:</strong> It is very strict about its design. If you need to change the style or keep the same look across React or Vue teams, you will find it limited.</p></li><li><p><strong>My Feedback:</strong> Community libraries like NG-ZORRO are good until you find a difficult bug. In a startup, time is money. Kendo UI enterprise support gets you help from the engineers who actually built the tools. This <strong>professional protection</strong> is why big companies prefer Kendo UI.</p></li></ul><p>If your focus is less on &ldquo;fancy&rdquo; and more on extreme accessibility and enterprise clean-room aesthetics, then check this out.</p><h2 id="clarity-design-system">9. Clarity Design System</h2><p><a target="_blank" href="https://clarity.design/">Clarity</a> is a design system developed by VMware. It was built for their own internal products and emphasizes a specific enterprise-style UX. While it&rsquo;s highly focused on its specific patterns, customizing it to fit a broader range of brand identities can be a challenge.</p><ul><li><p><strong>The Good:</strong> Strong focus on user experience and accessibility. It is built by VMware, so it is proven to work well for complex business tasks.</p></li><li><p><strong>The Cons:</strong> The look is very specific to VMware. It is difficult to change the style for a brand that wants to look unique.</p></li><li><p><strong>My Feedback:</strong> Clarity is very accessible, but it is hard to change. If your designers use Figma, Kendo UI is a much better choice. Progress Kendo UI provides <strong>Figma UI Kits</strong> that match the components exactly. This means your developers can build exactly what the designers created without mistakes.</p></li></ul><p>Finally, if you are the type of developer who loves full modularity and building your own patterns like LEGO, you&rsquo;ll love our final pick.</p><h2 id="taiga-ui">10. Taiga UI</h2><p><a target="_blank" href="https://taiga-ui.dev/">Taiga UI</a> is a library that focuses on modularity and a TypeScript-first approach. It&rsquo;s designed for developers who enjoy building their UI piece by piece, though this modularity often means a slower development cycle compared to more pre-integrated solutions.</p><ul><li><p><strong>The Good:</strong> It uses modular principles, making it perfect for developers who want to build their own patterns from zero.</p></li><li><p><strong>The Cons:</strong> Building a complex business dashboard this way is a slow process. In a startup, you don&rsquo;t have months to build every part; you have weeks to launch.</p></li><li><p><strong>My Feedback:</strong> Taiga UI is fun for small experiments, but for real business, you need speed. Kendo UI gives you the same modular power but with <strong>120+ ready-to-use components</strong>. You don&rsquo;t have to build the &ldquo;LEGO blocks&rdquo; yourself. Kendo UI gives you the whole castle ready to use.</p></li></ul><h2 id="recap">Recap</h2><p>Today, building software is a team effort. It is for designers, developers and AI agents. Choosing a framework that thinks about all these factors is the key to a successful product.</p><p>In 2026, picking a framework is a strategic decision that defines the success of your project. Choosing <strong>Kendo UI for Angular</strong> means giving your team the best tools for modern development. With features like the <a target="_blank" href="https://www.telerik.com/mcp-servers"><strong>MCP Server</strong></a>, <a target="_blank" href="https://themebuilder.telerik.com/"><strong>ThemeBuilder</strong></a> and <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-components"><strong>AI-ready components</strong></a>, Kendo UI for Angular helps you build applications faster and handle future challenges.</p><p><strong>Do you want to try it?</strong> </p><p><a target="_blank" href="https://www.telerik.com/try/kendo-angular-ui" class="Btn">Download Free Trial</a></p><img src="https://feeds.telerik.com/link/10827/17320248.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:156049da-af6d-45bc-9ca5-40a634a963f3</id>
    <title type="text">AI Productivity for React Developers in 2026</title>
    <summary type="text">Developers are not blindly handing work over to AI, but treating it as a strategic assistant. Here’s what this looks like for React devs in 2026.</summary>
    <published>2026-04-13T16:03:30Z</published>
    <updated>2026-04-18T12:15:37Z</updated>
    <author>
      <name>Hassan Djirdeh </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17318467/ai-productivity-react-developers-2026"/>
    <content type="text"><![CDATA[<p><span class="featured">Developers are not blindly handing work over to AI, but treating it as a strategic assistant. Here&rsquo;s what this looks like for React devs in 2026.</span></p><p>The 2025 Stack Overflow Developer Survey confirmed what most of us already know from experience: <a target="_blank" href="https://survey.stackoverflow.co/2025/ai/#1-ai-tools-in-the-development-process">84% of developers are now using or planning to use AI tools in their development process.</a> What&rsquo;s more revealing is how developers are still being cautious in their use of these tools. Only about <a target="_blank" href="https://survey.stackoverflow.co/2025/ai/#2-accuracy-of-ai-tools">one-third say they trust AI outputs completely, while nearly half question their accuracy</a>.</p><p>This cautious adoption tells us something important. We&rsquo;re not blindly handing our work over to AI. We&rsquo;re learning to use these tools strategically, treating them as assistants rather than replacements. For React developers specifically, this means adapting how we approach building interfaces, managing component libraries and iterating on features.</p><p>If you&rsquo;ve been building React applications for a while, you&rsquo;ve probably experienced this shift firsthand. Maybe you&rsquo;re using <a target="_blank" href="https://github.com/features/copilot">GitHub Copilot</a> to autocomplete component logic, or <a target="_blank" href="https://cursor.com/">Cursor</a> to refactor entire feature branches. Perhaps you&rsquo;re generating design themes with <a target="_blank" href="https://www.telerik.com/themebuilder">Progress ThemeBuilder</a>, or using <a target="_blank" href="https://claude.ai/">Claude</a> to debug complex state management issues. These aren&rsquo;t experimental workflows anymore; they&rsquo;re part of how we work.</p><p>In this article, we&rsquo;ll explore what this actually looks like in practice for React developers in 2026.</p><h2 id="coding-itself-has-changed">Coding Itself Has Changed</h2><p>There&rsquo;s a shift in how we write code, and it&rsquo;s not what most people expected (don&rsquo;t worry, we&rsquo;re not being replaced by AI). We&rsquo;re spending less time on the mechanical act of typing and more time on the creative work of guiding and refining.</p><p><a target="_blank" href="https://tinyclouds.org/">Ryan Dahl</a>, the creator of <a target="_blank" href="https://nodejs.org/en">Node.js</a> and <a target="_blank" href="https://deno.com/">Deno</a>, aptly put it in a recent social media post: <em>&ldquo;This has been said a thousand times before, but allow me to add my own voice: the era of humans writing code is over. Disturbing for those of us who identify as SWEs, but no less true. That&rsquo;s not to say SWEs don&rsquo;t have work to do, but writing syntax directly is not it.&rdquo;</em></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/ai-productivity-for-react-ryan-dahl-x-post.png?sfvrsn=6d572b2c_2" alt="" /></p><p>For React developers, this means our day-to-day work looks different. Instead of spending an hour carefully typing out a form component with all its validation logic, we might spend 10 minutes describing what we need and then another 20 minutes reviewing and adjusting the generated code. The result? The same quality component in a fraction of the time.</p><p>The iteration cycles have also become faster. When we can generate and refine code quickly, we&rsquo;re more willing to try multiple approaches. Need to see how our data grid looks with server-side pagination versus client-side? Generate both implementations and compare them. Want to experiment with different state management patterns? We can prototype each one in minutes rather than hours.</p><p>We still need to understand React&rsquo;s rendering model, still need to know when to use <code>useCallback</code> versus <code>useMemo</code>, still need to architect our component hierarchy thoughtfully. However, we don&rsquo;t need to manually type out every property definition or write boilerplate code repeatedly.</p><h2 id="continuous-context-and-ai-native-editors">Continuous Context and AI-Native Editors</h2><p>One of the significant improvements in AI-assisted development is <strong>persistent context</strong>. Modern AI coding assistants understand our entire codebase, not just the file we&rsquo;re currently editing.</p><p>Traditional autocomplete tools could only see a few lines around our cursor. They might suggest completing a function name, but they had no idea what that function should actually do or how it fit into our broader application architecture. AI-native editors and tools like <a target="_blank" href="https://cursor.com/">Cursor</a>, <a target="_blank" href="https://code.claude.com/docs/en/overview">Claude Code</a> and others have changed this completely.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/ai-productivity-for-react-cursor.jpg?sfvrsn=e557aff2_2" alt="" /></p><p>These tools help maintain an understanding of our project structure, our component patterns, our naming conventions and even our coding style. When we ask them to create a new feature, they don&rsquo;t just generate generic React code; they generate code that looks like it belongs in our codebase because they&rsquo;ve learned from the rest of our application.</p><p>Let&rsquo;s say we&rsquo;re building a <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/sample-applications/admin-dashboard">React dashboard</a> UI that needs to fetch user data and display it in a <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/grid">table</a>. With traditional tools, we&rsquo;d manually wire up the API call, handle loading states, manage errors and set up the table structure.</p><p>With an AI assistant that understands our codebase, we can describe what we need, and it&rsquo;ll generate code that uses our existing API client, follows our established error handling patterns and implements the table using whatever libraries we&rsquo;re already using in our app.</p><p>Working with these AI assistants feels less like using a tool and more like pair programming with someone who already knows our codebase inside and out.</p><h2 id="planning-and-agentic-workflows">Planning and Agentic Workflows</h2><p>Writing individual functions or components is one thing, but modern AI tools are increasingly capable of handling multi-step workflows that require planning and coordination. This is where agentic AI comes in: systems that can break down complex tasks into smaller steps and execute them sequentially or in parallel.</p><p>For React developers, this means we can hand off entire features to an AI agent rather than just asking for help with specific files. Want to migrate from <a target="_blank" href="https://redux.js.org/">Redux</a> to <a target="_blank" href="https://github.com/pmndrs/zustand">Zustand</a>? An AI agent can analyze our current state management setup, create a migration plan, and then systematically work through each component to update the implementation.</p><p>For example, we might tell an agent: <em>&ldquo;Build a column chart that shows quarterly sales by region, with drill-down functionality to reveal monthly data when a quarter is clicked.&rdquo;</em></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/kendoreact-chart-mcp.gif?sfvrsn=86c7ffc8_1" alt="" /></p><p>The agent can generate the chart component, configure the data bindings, create any necessary helper functions for aggregation and even add default styling or tooltips.</p><p>What&rsquo;s powerful is that these agents can handle refactors and migrations that would be tedious to do manually. Need to rename a prop across 50 components? Want to update all your class components to functional components with hooks? Planning to migrate from JavaScript to TypeScript? These are exactly the kinds of repetitive-but-important tasks that agents excel at.</p><h2 id="ui-generation-design-and-theming-with-ai">UI Generation, Design and Theming with AI</h2><p>Building user interfaces has always involved a fair amount of repetitive work. Creating layouts, styling components and maintaining design consistency across an application. These are all necessary tasks, but they&rsquo;re not where some developers want to spend their creative energy.</p><p>With AI, layout generation has become surprisingly sophisticated. Tools like <a target="_blank" href="https://v0.dev/">v0</a> can take a description or even a screenshot of a design and generate React components that implement that layout. The code they produce isn&rsquo;t just a rough approximation either, it&rsquo;s good-quality JSX with proper semantic HTML, accessibility attributes and responsive styling.</p><p>For React developers working with component libraries like <a target="_blank" href="https://www.telerik.com/kendo-react-ui">Progress KendoReact</a>, this gets even more powerful as long as the agent has the appropriate context about the library and components. Instead of generating generic HTML and CSS, these tools can generate code using the actual components from our library. Need a data grid with sorting, filtering and pagination? Describe it, and the AI will scaffold it using the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/grid">React Grid</a> component we&rsquo;re already using elsewhere in our app: with all the right props, event handlers and styling.</p><p><a target="_blank" href="https://www.telerik.com/themebuilder">Progress ThemeBuilder</a> has taken this a step further with AI-powered theme generation. Instead of manually configuring dozens of color variables and spacing values, we can describe the aesthetic we&rsquo;re going for in plain English: <em>&ldquo;Create a clean, modern analytics theme with a cool blue-gray palette that feels data-driven and professional, suitable for a B2B software dashboard.&rdquo;</em> The AI generates a complete design system that applies consistently across all our components.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/theme-builder-modern-analytics-theme.png?sfvrsn=8a4ac335_2" alt="" /></p><p>What makes this valuable is that the generated themes aren&rsquo;t just random color combinations. The AI understands design principles like color theory, contrast ratios for accessibility and how different UI states should relate visually. When it generates a theme, it&rsquo;s creating a system where primary buttons, hover states, focus indicators and disabled states all work together. ThemeBuilder also provides component-level AI theming, which means we can refine specific components without having to regenerate our entire theme.</p><p>For developers who aren&rsquo;t designers (which is most of us), this removes a huge source of friction. We can focus on building functionality while still delivering applications that look professional and cohesive.</p><h2 id="model-context-protocol-and-integration">Model Context Protocol and Integration</h2><p>The tools we&rsquo;ve talked about so far are impressive, but they have a limitation: they only know what&rsquo;s in our codebase and what they learned during training. They don&rsquo;t know about our specific component library&rsquo;s latest features, our company&rsquo;s internal design system, or the proprietary APIs we&rsquo;re building against.</p><p>This is where <a target="_blank" href="https://modelcontextprotocol.io/docs/getting-started/intro">Model Context Protocol (MCP)</a> becomes important. Think of MCP as a standardized way for AI models to connect to external knowledge sources and tools. Instead of the AI being limited to its training data, it can reach out to documentation, component libraries, databases and other resources to get current, specific information about the tools we&rsquo;re using.</p><p>For React developers, this means our AI assistant can understand the actual API of the components we&rsquo;re working with, not just generic React patterns. When we&rsquo;re using the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/grid">KendoReact Grid</a> component, an MCP-enabled assistant can query the real documentation to understand what props are available, what patterns are recommended and what changed in the latest version.</p><p>The <a target="_blank" href="https://www.npmjs.com/package/@progress/kendo-react-mcp">@progress/kendo-react-mcp</a> server implements this for KendoReact. When we install it and configure it with our editor, the AI assistant gains access to comprehensive knowledge about KendoReact components. It&rsquo;s not guessing at how to use the Grid, or the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/scheduler">Scheduler</a>, or the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/dateinputs/datepicker">DatePicker</a>. It&rsquo;s referencing the actual documentation and best practices.</p><p>Here&rsquo;s an example of generating a KendoReact Grid from scratch with the help of the <code>@progress/kendo-react-mcp</code> tool.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/kendoreact-grid-mcp.gif?sfvrsn=98fc03b_2" alt="" /></p><p>This can make a large difference in practice. Without MCP, we might ask an AI to create a KendoReact Grid component and get something that looks right but uses outdated props or misses important configuration options. With MCP, the AI generates code that follows current best practices and uses the component exactly as it was designed to be used.</p><h2 id="quality-review-and-governance">Quality, Review and Governance</h2><p>As AI-generated code becomes more prevalent in React applications, questions about quality and review processes naturally arise. The good news is that AI isn&rsquo;t just generating code; it&rsquo;s starting to get better at reviewing and improving it.</p><p>Modern AI tools can perform code reviews that go beyond syntax checking. They understand architectural patterns, can spot potential performance issues and flag accessibility concerns. When we commit changes, these tools can analyze the diff and provide feedback similar to what a developer might offer in a pull request review.</p><p>For React applications specifically, this means AI can catch issues like unnecessary re-renders, missing dependency arrays in hooks, improper state management patterns or components that should be memoized but aren&rsquo;t. It can also verify that our components follow established patterns in our codebase and flag when new code deviates from those conventions.</p><p>AI-generated code can greatly accelerate development and improve consistency, but <strong>it&rsquo;s not a replacement for human judgment</strong>. Even the more sophisticated tools benefit from a steward: a developer who reviews, guides and validates the AI&rsquo;s output. Humans remain essential for making nuanced decisions, verifying alignment with project goals and upholding quality standards that AI alone can&rsquo;t fully guarantee. In other words, AI can handle the heavy (repetitive) lifting, but the final responsibility still rests with us.</p><h2 id="what-this-means-for-day-to-day-react-work">What This Means for Day-to-Day React Work</h2><p>What does all of this actually look like in practice? How has the daily experience of building React applications changed? Here are some takeaways:</p><ul><li><strong>Faster iteration</strong>: Features that used to take days can now be scaffolded in hours. AI handles repetitive boilerplate, letting us focus on logic, architecture and user experience.</li><li><strong>Less boilerplate, more creativity</strong>: Forms, API integrations, responsive layouts and other common patterns can be generated automatically, freeing us to solve higher-level problems.</li><li><strong>Higher-level decisions matter more</strong>: Understanding React fundamentals like component composition, state management, performance optimization and accessibility is more important than ever because we&rsquo;re guiding and reviewing AI outputs rather than typing everything ourselves.</li></ul><p>In short, React development in 2026 is faster, more iterative and more creative. The mechanical work of writing boilerplate and translating designs into components is largely automated, but the critical thinking and stewardship still require skilled developers.</p><h2 id="ready-to-explore-how-ai-can-enhance-your-react-development">Ready to Explore How AI Can Enhance Your React Development?</h2><ul><li>Give the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-components#kendoreact-ai-components-and-features">KendoReact AI Components and Features</a> a try.</li><li>Watch demos of <a target="_blank" href="https://www.telerik.com/themebuilder">AI-powered theme generation in ThemeBuilder</a> to see how design ideation can be automated.</li><li>Try the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-tools/ai-assistant/getting-started">KendoReact MCP Server</a> to give your AI assistant deep knowledge of KendoReact components.</li><li>Check out the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-tools/ai-assistant/prompt-library">KendoReact Prompt Library</a> for ready-made prompts that target common development scenarios.</li></ul><img src="https://feeds.telerik.com/link/10827/17318467.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:bd4d6447-7473-40eb-b916-7931c305c4b7</id>
    <title type="text">Simplified Authentication with Better Auth</title>
    <summary type="text">We’ll build a complete email and password authentication system with session management to see how Better Auth works. Users will be able to sign up, log in and stay authenticated across page refreshes. We’ll use Next.js, Drizzle ORM and SQLite.</summary>
    <published>2026-04-09T17:26:49Z</published>
    <updated>2026-04-18T12:15:37Z</updated>
    <author>
      <name>Christian Nwamba </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17316560/simplified-authentication-better-auth"/>
    <content type="text"><![CDATA[<p><span class="featured">We&rsquo;ll build a complete email and password authentication system with session management to see how Better Auth works. Users will be able to sign up, log in and stay authenticated across page refreshes. We&rsquo;ll use Next.js, Drizzle ORM and SQLite.</span></p><p>Authentication should be straightforward, but in practice, it takes time. You&rsquo;re dealing with sessions, cookies, password hashing, OAuth redirects and email verification, and each piece has its own quirks and scattered documentation. The whole time, you may also be asking yourself if you&rsquo;re doing this securely. One mistake exposes your users.</p><p>Most existing tools don&rsquo;t help much. <a target="_blank" href="https://next-auth.js.org/">NextAuth</a> is solid if you&rsquo;re using Next.js, but switching frameworks means starting over. Building from scratch gives you control at the cost of maintaining every security detail yourself. <a target="_blank" href="https://clerk.com/">Clerk</a> and <a target="_blank" href="https://auth0.com/">Auth0</a> work well until you reach their pricing tiers or require a feature they don&rsquo;t support. <a target="_blank" href="https://www.passportjs.org/">Passport.js</a> works, but it hasn&rsquo;t aged well&mdash;there&rsquo;s callback hell and endless boilerplate.</p><p><a target="_blank" href="https://www.better-auth.com/">Better Auth</a> takes a different approach. It&rsquo;s lightweight, works with any framework (<a target="_blank" href="https://nextjs.org/">Next.js</a>, <a target="_blank" href="https://remix.run/">Remix</a>, <a target="_blank" href="https://svelte.dev/">Svelte</a>, etc.), and comes with <a target="_blank" href="https://www.typescriptlang.org/">TypeScript</a> baked in. You get OAuth, 2FA and password resets out of the box. You can also customize when you need to, or just use the defaults.</p><p>In this guide, we&rsquo;ll build a complete email and password authentication system with session management to see how Better Auth works. Users will be able to sign up, log in and stay authenticated across page refreshes. We&rsquo;ll use Next.js, Drizzle ORM and SQLite.</p><h2 id="prerequisites">Prerequisites</h2><p>To follow along with this guide, you&rsquo;ll need:</p><ul><li>A decent understanding of JavaScript/TypeScript</li><li>Basic familiarity with React and Next.js</li><li>A database ready (<a target="_blank" href="https://www.postgresql.org/">PostgreSQL</a>, <a target="_blank" href="https://www.mysql.com/">MySQL</a> or <a target="_blank" href="https://sqlite.org/">SQLite</a>)</li></ul><h2 id="what-is-better-auth">What Is Better Auth?</h2><p>Better Auth is a TypeScript-first authentication library that avoids the usual trade-offs like vendor lock-in, expensive monthly fees or complex configurations. It is framework-agnostic, so you can use it with Next.js today and switch to Remix or SvelteKit tomorrow without rewriting your auth logic. It&rsquo;s not a managed service, so there&rsquo;s no per-user pricing or vendor lock-in.</p><p>What makes it different? It&rsquo;s database-agnostic, meaning you can use PostgreSQL, MySQL, SQLite or MongoDB. Better Auth adapts through adapters like Prisma, Drizzle and Mongoose. It&rsquo;s type-safe by default, built in TypeScript from the ground up, so your IDE knows what methods exist, what data comes back, and catches errors before you run your code. It also has security measures built in by default, with proper password hashing, HttpOnly cookies, CSRF protection and secure session management. The defaults follow best practices.</p><p>Better Auth supports OAuth providers (Google, GitHub, etc.), magic links, two-factor authentication, passkeys, even enterprise SSO, and more than what we&rsquo;ll cover in this article. We&rsquo;re focusing on the fundamentals so you understand how the system works. Once you grasp the basics, adding these features is straightforward through Better Auth&rsquo;s plugin system.</p><h2 id="project-setup">Project Setup</h2><p>Let&rsquo;s start by creating a new Next.js project with TypeScript and <a target="_blank" href="https://tailwindcss.com/">Tailwind CSS</a>. Run the following command in your terminal:</p><pre class=" language-shell"><code class="prism  language-shell">npx create-next-app@latest better-auth --ts --tailwind --eslint --app
</code></pre><p>This creates a Next.js project with TypeScript, Tailwind CSS, ESLint and App Router (the modern Next.js routing system) configured.</p><p>Run this command to navigate into the project:</p><pre class=" language-shell"><code class="prism  language-shell">cd better-auth
</code></pre><p>Run the following command to install Better Auth and its dependencies:</p><pre class=" language-shell"><code class="prism  language-shell">npm install better-auth drizzle-orm better-sqlite3 
npm install -D drizzle-kit @types/better-sqlite3
</code></pre><h2 id="database-setup">Database Setup</h2><p>Before configuring Better Auth, we need to prepare our database. We&rsquo;ll break this down into three distinct files to keep things organized:</p><ul><li><strong>Define the tables</strong>: Create the tables Better Auth needs (users, sessions, accounts, verification)</li><li><strong>Database initialization</strong>: Set up the SQLite connection and wrap it with Drizzle for type-safe queries</li><li><strong>Configure auth</strong>: Finally, we connect our database to Better Auth using the Drizzle adapter</li></ul><h3 id="define-the-tables">Define the Tables</h3><p>We need to explicitly define the tables Better Auth expects. We will add all of these to a single file. Open your <code>lib/auth-schema.ts</code> file and add the following to it:</p><p><strong>The User Table</strong><br />This stores basic user information.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token comment">//lib/auth-schema.ts</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> sqliteTable<span class="token punctuation">,</span> text<span class="token punctuation">,</span> integer <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"drizzle-orm/sqlite-core"</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token function">sqliteTable</span><span class="token punctuation">(</span><span class="token string">"user"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"id"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">primaryKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  name<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"name"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  email<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"email"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unique</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  emailVerified<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"emailVerified"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"boolean"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  image<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"image"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  createdAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"createdAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  updatedAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"updatedAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The <code>email</code> field is unique, meaning no two users can share the same email. Better Auth requires these specific fields for its internal functionality.</p><p>Notice we mark <code>name</code> and <code>email</code> as <code>notNull()</code> here. This is important because Better Auth infers its types from this schema. By making them required in the database, TypeScript will automatically force us to provide them in the sign-up form later.</p><p><strong>The Session Table</strong><br />This manages active login sessions.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token comment">//lib/auth-schema.ts</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> session <span class="token operator">=</span> <span class="token function">sqliteTable</span><span class="token punctuation">(</span><span class="token string">"session"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"id"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">primaryKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  expiresAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"expiresAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  token<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"token"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unique</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  createdAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"createdAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  updatedAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"updatedAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  ipAddress<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"ipAddress"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  userAgent<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"userAgent"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  userId<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"userId"</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">references</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> user<span class="token punctuation">.</span>id<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>Each session has a unique token and links to a user via <code>userId</code>. The <code>expiresAt</code> timestamp determines when the session becomes invalid.</p><p><strong>The Account Table</strong><br />This handles OAuth providers and stores authentication credentials.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token comment">//lib/auth-schema.ts</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> account <span class="token operator">=</span> <span class="token function">sqliteTable</span><span class="token punctuation">(</span><span class="token string">"account"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"id"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">primaryKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  accountId<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"accountId"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  providerId<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"providerId"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  userId<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"userId"</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">references</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> user<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">,</span>
  accessToken<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"accessToken"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  refreshToken<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"refreshToken"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  idToken<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"idToken"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  accessTokenExpiresAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"accessTokenExpiresAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  refreshTokenExpiresAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"refreshTokenExpiresAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  scope<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"scope"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  password<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"password"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  createdAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"createdAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  updatedAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"updatedAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The account table stores the user&rsquo;s credentials, including the password. This separation keeps the architecture flexible, allowing you to link other providers like GitHub or Google to the same user identity.</p><p><strong>Verification Table</strong><br />This stores temporary code for email verification and password resets.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">const</span> verification <span class="token operator">=</span> <span class="token function">sqliteTable</span><span class="token punctuation">(</span><span class="token string">"verification"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"id"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">primaryKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  identifier<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"identifier"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  value<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"value"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  expiresAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"expiresAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  createdAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"createdAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  updatedAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"updatedAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</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>This table acts as a temporary vault for security tokens. When the system sends an email to verify a user, the unique code is stored here to ensure the link is valid and hasn&rsquo;t expired when clicked.</p><h3 id="database-initialization">Database Initialization</h3><p>We need a running database connection. Let&rsquo;s create a file called <code>lib/db.ts</code>. This is where we initialize SQLite and wrap it in Drizzle so we can use it everywhere else. We wrap it because we want to write TypeScript, not SQL strings. By passing the connection to Drizzle, you get to query your database using typed methods.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token comment">// lib/db.ts </span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> drizzle <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"drizzle-orm/better-sqlite3"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> Database <span class="token keyword">from</span> <span class="token string">"better-sqlite3"</span><span class="token punctuation">;</span>

<span class="token comment">// This creates a local 'sqlite.db' file if it doesn't exist</span>
<span class="token keyword">const</span> sqlite <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Database</span><span class="token punctuation">(</span><span class="token string">"sqlite.db"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 

<span class="token keyword">export</span> <span class="token keyword">const</span> db <span class="token operator">=</span> <span class="token function">drizzle</span><span class="token punctuation">(</span>sqlite<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>We need to do this first so we can import <code>db</code> into our auth configuration without TypeScript yelling at us.</p><h3 id="configure-auth">Configure Auth</h3><p>Now we can write the auth config. This file is where we tell Better Auth about our database and configure how users will authenticate.</p><p>Create a <code>lib/auth.ts</code> file and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token comment">//lib/auth.ts</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> betterAuth <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"better-auth"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> drizzleAdapter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"better-auth/adapters/drizzle"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> db <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./db"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> schema <span class="token keyword">from</span> <span class="token string">"./auth-schema"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> auth <span class="token operator">=</span> <span class="token function">betterAuth</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  database<span class="token punctuation">:</span> <span class="token function">drizzleAdapter</span><span class="token punctuation">(</span>db<span class="token punctuation">,</span> <span class="token punctuation">{</span>
    provider<span class="token punctuation">:</span> <span class="token string">"sqlite"</span><span class="token punctuation">,</span>
    schema<span class="token punctuation">:</span> schema<span class="token punctuation">,</span> <span class="token comment">// passing the schema here</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  emailAndPassword<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    enabled<span class="token punctuation">:</span> <span class="token keyword">true</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre><p>In the code above, we import the database connection <code>db</code> and <code>schema</code> we created, then pass them to Better Auth through the drizzleAdapter. This adapter translates Better Auth operations into Drizzle queries so it can read and write user data.</p><p>The <code>provider: "sqlite"</code> tells Better Auth we&rsquo;re using SQLite. If we were using something else like PostgreSQL, we would change it to whatever we&rsquo;re using.</p><p>It is important to note that the <code>emailAndPassword: {enabled: true}</code> option activates email and password authentication. Better Auth will generate the signup and signin endpoints we need.</p><h2 id="syncing-database">Syncing Database</h2><p>Now that we have three core files, we need to create the database file. Currently, <code>sqlite.db</code> doesn&rsquo;t exist.</p><h3 id="drizzle-configuration">Drizzle Configuration</h3><p>Create a file named <code>drizzle.config.ts</code> at the your root of your project and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token comment">//drizzle.config.ts</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> defineConfig <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"drizzle-kit"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token function">defineConfig</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  schema<span class="token punctuation">:</span> <span class="token string">"./lib/auth-schema.ts"</span><span class="token punctuation">,</span> <span class="token comment">// where our tables will be defined</span>
  dialect<span class="token punctuation">:</span> <span class="token string">"sqlite"</span><span class="token punctuation">,</span>
  dbCredentials<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    url<span class="token punctuation">:</span> <span class="token string">"sqlite.db"</span><span class="token punctuation">,</span> <span class="token comment">// This is the name of the file it will create</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>Here, we tell Drizzle where to find our schema and what database to use. The config points to our schema file <code>./lib/auth-schema.ts</code> and specifies SQLite as the database type. The url is the filename Drizzle will create and in this case, it&rsquo;s <code>sqlite.db</code>.</p><p>Now, run this command in your terminal to sync your code with the database:</p><pre class=" language-shell"><code class="prism  language-shell">npx drizzle-kit push
</code></pre><p>If everything is set up correctly, you should see a success message. Drizzle just created a local <code>sqlite.db</code> file in your project root with all your user, session and account tables.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/drizzle-configuration.png?sfvrsn=8da70ecc_2" title="Drizzle configurations" alt="Drizzle configuration" /></p><h2 id="api-route">API Route</h2><p>Now we need to set up an API route so our frontend can communicate with Better Auth. Create a file named <code>app/api/auth/[...all]/route.ts</code>. This will be the API route that handles all auth requests:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token comment">// app/api/auth/[...all]/route.ts</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span> auth <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/lib/auth"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> toNextJsHandler <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"better-auth/next-js"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> GET<span class="token punctuation">,</span> POST <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">toNextJsHandler</span><span class="token punctuation">(</span>auth<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><blockquote><p>If your project uses <code>src/</code>, this goes in <code>src/api/auth/[...all]/route.ts</code>.</p></blockquote><h2 id="auth-client">Auth Client</h2><p>Finally, for our setup, we need a way for our frontend to talk to the backend without writing messy fetch calls.</p><p>Create <code>lib/auth-client.ts</code> file and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> createAuthClient <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"better-auth/react"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> authClient <span class="token operator">=</span> <span class="token function">createAuthClient</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  baseURL<span class="token punctuation">:</span> <span class="token string">"http://localhost:3000"</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 small utility will give us type-safe methods for signing in, signing up and checking sessions.</p><h2 id="email-and-password-authentication">Email and Password Authentication</h2><p>Now let&rsquo;s build the authentication forms. We&rsquo;ll create two components: one for sign-up and one for sign-in.</p><h3 id="sign-up-form">Sign-up Form</h3><p>Create a file named <code>components/sign-up.tsx</code> and add the following to it:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token comment">// components/sign-up.tsx</span>
<span class="token string">"use client"</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> authClient <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/lib/auth-client"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"next/navigation"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">SignUp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>email<span class="token punctuation">,</span> setEmail<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>password<span class="token punctuation">,</span> setPassword<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>name<span class="token punctuation">,</span> setName<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>isLoading<span class="token punctuation">,</span> setIsLoading<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</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 keyword">const</span> router <span class="token operator">=</span> <span class="token function">useRouter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> signUp <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">await</span> authClient<span class="token punctuation">.</span>signUp<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span>
      <span class="token punctuation">{</span>
        email<span class="token punctuation">,</span>
        password<span class="token punctuation">,</span>
        name<span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        onRequest<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token function">setIsLoading</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>
        onSuccess<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">"/dashboard"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        onError<span class="token punctuation">:</span> <span class="token punctuation">(</span>ctx<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token function">alert</span><span class="token punctuation">(</span>ctx<span class="token punctuation">.</span>error<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token function">setIsLoading</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>
      <span class="token punctuation">}</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">return</span> <span class="token punctuation">(</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col gap-4 w-full max-w-md mx-auto mt-10 border border-gray-200 p-6 rounded-lg shadow-sm 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>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-xl font-bold text-gray-900<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Create Account<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">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col 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>label</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm font-medium text-gray-700<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
        <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span>
        <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>name<span class="token punctuation">}</span></span>
        <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</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 function">setName</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
        <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>John Doe<span class="token punctuation">"</span></span>
        <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>border border-gray-300 p-2 rounded focus:outline-none focus:ring-2 focus:ring-black text-black 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>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">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col 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>label</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm font-medium text-gray-700<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Email<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
        <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span>
        <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>email<span class="token punctuation">}</span></span>
        <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</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 function">setEmail</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
        <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>user@example.com<span class="token punctuation">"</span></span>
        <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>border border-gray-300 p-2 rounded focus:outline-none focus:ring-2 focus:ring-black text-black 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>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">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col 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>label</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm font-medium text-gray-700<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Password<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
        <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span>
        <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>password<span class="token punctuation">}</span></span>
        <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</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 function">setPassword</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
        <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;<span class="token punctuation">"</span></span>
        <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>border border-gray-300 p-2 rounded focus:outline-none focus:ring-2 focus:ring-black text-black 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>div</span><span class="token punctuation">&gt;</span></span>

    <span class="token operator">&lt;</span>button
      onClick<span class="token operator">=</span><span class="token punctuation">{</span>signUp<span class="token punctuation">}</span>
      disabled<span class="token operator">=</span><span class="token punctuation">{</span>isLoading<span class="token punctuation">}</span>
      className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token string">`mt-2 p-2 rounded text-white font-medium transition-colors </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>
        isLoading
          <span class="token operator">?</span> <span class="token string">"bg-gray-400 cursor-not-allowed"</span>
          <span class="token punctuation">:</span> <span class="token string">"bg-black hover:bg-gray-800"</span>
      <span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">}</span>
    <span class="token operator">&gt;</span>
      <span class="token punctuation">{</span>isLoading <span class="token operator">?</span> <span class="token string">"Creating an account..."</span> <span class="token punctuation">:</span> <span class="token string">"Sign Up"</span><span class="token punctuation">}</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token punctuation">)</span><span class="token punctuation">;</span> 
</code></pre><p>This component handles the entire sign-up flow in a single file. If you look closer, you&rsquo;ll see that the heavy lifting is done by <code>authClient.signUp.email()</code>. This function is type-safe and accepts two distinct arguments (the payload and the event handlers):</p><ul><li><strong>The payload</strong>: This is the actual data we&rsquo;re sending. In this case, email, password and name. Since our database schema requires these fields, the client verifies we actually provide them. If we miss a required field, TypeScript will flag it instantly.</li><li><strong>Event handlers</strong>: The second argument is an object that controls the request lifecycle, from the moment we click Sign Up to when we get a result. This is one of the perks of Better Auth because it replaces try/catch blocks with clean event hooks. All we have to do is define what happens at each stage: <code>onRequest</code>, <code>onSuccess</code> and <code>onError</code>, which catches errors and alerts the user in this case.</li></ul><h2 id="sign-in-form">Sign-in Form</h2><p>With our current setup, users can only register. We need to log them in if they&rsquo;re existing users.</p><p>Create a file named <code>components/sign-in.tsx</code> and add the following to it:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token comment">//components/sign-in.tsx</span>
<span class="token string">"use client"</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> authClient <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/lib/auth-client"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"next/navigation"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">SignIn</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>email<span class="token punctuation">,</span> setEmail<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>password<span class="token punctuation">,</span> setPassword<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>isLoading<span class="token punctuation">,</span> setIsLoading<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</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 keyword">const</span> router <span class="token operator">=</span> <span class="token function">useRouter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> signIn <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">await</span> authClient<span class="token punctuation">.</span>signIn<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span>
      <span class="token punctuation">{</span>
        email<span class="token punctuation">,</span>
        password<span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        onRequest<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token function">setIsLoading</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>
        onSuccess<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token function">setIsLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">"/dashboard"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        onError<span class="token punctuation">:</span> <span class="token punctuation">(</span>ctx<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token function">setIsLoading</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 function">alert</span><span class="token punctuation">(</span>ctx<span class="token punctuation">.</span>error<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token 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">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col gap-4 w-full max-w-md mx-auto mt-10 border border-gray-200 p-6 rounded-lg shadow-sm 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>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-xl font-bold text-gray-900<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Sign In<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">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col 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>label</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm font-medium text-gray-700<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Email<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
          <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span>
          <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>email<span class="token punctuation">}</span></span>
          <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</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 function">setEmail</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
          <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>user@example.com<span class="token punctuation">"</span></span>
          <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>border border-gray-300 p-2 rounded focus:outline-none focus:ring-2 focus:ring-black text-black 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>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">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col 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>label</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm font-medium text-gray-700<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Password<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
          <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span>
          <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>password<span class="token punctuation">}</span></span>
          <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</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 function">setPassword</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
          <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;<span class="token punctuation">"</span></span>
          <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>border border-gray-300 p-2 rounded focus:outline-none focus:ring-2 focus:ring-black text-black 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>div</span><span class="token punctuation">&gt;</span></span>

      <span class="token operator">&lt;</span>button
        onClick<span class="token operator">=</span><span class="token punctuation">{</span>signIn<span class="token punctuation">}</span>
        disabled<span class="token operator">=</span><span class="token punctuation">{</span>isLoading<span class="token punctuation">}</span>
        className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token string">`mt-2 p-2 rounded text-white font-medium transition-colors </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>
          isLoading
            <span class="token operator">?</span> <span class="token string">"bg-gray-400 cursor-not-allowed"</span>
            <span class="token punctuation">:</span> <span class="token string">"bg-black hover:bg-gray-800"</span>
        <span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">}</span>
      <span class="token operator">&gt;</span>
        <span class="token punctuation">{</span>isLoading <span class="token operator">?</span> <span class="token string">"Loading..."</span> <span class="token punctuation">:</span> <span class="token string">"Sign In"</span><span class="token punctuation">}</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>This component is nearly identical to the sign-up form with one key difference: we only need email and password since we&rsquo;re verifying an existing user, not creating a new one.</p><p>When a user submits the form, Better Auth verifies the credentials against our database. If they match, it automatically creates a session and sets a secure HttpOnly cookie. This cookie persists the login state, so users stay logged in even after refreshing the page.</p><p>Remember when we enabled <code>emailAndPassword: { enabled: true }</code> in the <code>lib/auth.ts</code> file? Better Auth read that configuration and automatically generated this method for us.</p><p>Now let&rsquo;s create dedicated pages for these forms.</p><h2 id="creating-authentication-pages">Creating Authentication Pages</h2><p>Instead of embedding forms on the homepage, we&rsquo;ll create dedicated routes for sign-in, sign-up and a dashboard to verify successful login.</p><h3 id="sign-up-page">Sign-up Page</h3><p>Create a component called <code>app/signup/page.tsx</code> and add the following to it:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token comment">//app/signup/page.tsx</span>
<span class="token keyword">import</span> SignUp <span class="token keyword">from</span> <span class="token string">"@/components/sign-up"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> Link <span class="token keyword">from</span> <span class="token string">"next/link"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">SignUpPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col items-center justify-center min-h-screen bg-gray-50<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>SignUp</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">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mt-6 text-center text-sm text-gray-600<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        Already have an account<span class="token operator">?</span><span class="token punctuation">{</span><span class="token string">" "</span><span class="token punctuation">}</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Link</span>
          <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/signin<span class="token punctuation">"</span></span>
          <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-blue-600 font-medium hover:underline<span class="token punctuation">"</span></span>
        <span class="token punctuation">&gt;</span></span>
          Sign In
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Link</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 punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>This page wraps the <code>&lt;SignUp /&gt;</code> component and adds a <code>link</code> to sign in.</p><h3 id="sign-in-page">Sign-in Page</h3><p>Create a component called <code>app/signin/page.tsx</code> and add the following to it:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token comment">//app/signin/page.tsx</span>
<span class="token keyword">import</span> SignIn <span class="token keyword">from</span> <span class="token string">"@/components/sign-in"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> Link <span class="token keyword">from</span> <span class="token string">"next/link"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">SignInPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col items-center justify-center min-h-screen bg-gray-50<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>SignIn</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">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mt-6 text-center text-sm text-gray-600<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        New <span class="token class-name">here</span><span class="token operator">?</span><span class="token punctuation">{</span><span class="token string">" "</span><span class="token punctuation">}</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Link</span>
          <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/signup<span class="token punctuation">"</span></span>
          <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-blue-600 font-medium hover:underline<span class="token punctuation">"</span></span>
        <span class="token punctuation">&gt;</span></span>
          Create an account
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Link</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 punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>This page wraps the <code>&lt;SignIn /&gt;</code> component and adds a link to Sign Up.</p><h3 id="dashboard-page">Dashboard Page</h3><p>We need a destination for users after they log in. For now, let&rsquo;s create a simple static page named <code>app/dashboard/page.tsx</code> and add the following to it:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token comment">//app/dashboard/page.tsx</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Dashboard</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col items-center justify-center min-h-screen bg-white text-black<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">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-3xl font-bold<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Dashboard<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mt-4 text-gray-600<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>You are successfully logged <span class="token keyword">in</span><span class="token operator">!</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><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>Now you can start your server by running <code>npm run dev</code> and then open <a target="_blank" href="http://localhost:3000">http://localhost:3000</a>.</p><p>You should see a landing page with options to Sign In or Create Account. Follow these steps to test the authentication:</p><ul><li>Click &ldquo;Create Account&rdquo; and create a new user. If it works, you should be redirected to the dashboard.</li><li>To test the login form, you don&rsquo;t need to open another window. Just hit the back button in your browser to return to the landing page. Click &ldquo;Sign In&rdquo; this time, enter the email and password you just used to sign up, and watch it redirect you back to the dashboard.</li></ul><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/sign-up-and-redirect.gif?sfvrsn=eb3db7f9_2" title="Testing the Sign Up and Redirect flow" alt="Testing the Sign Up and Redirect flow" /></p><h2 id="accessing-user-sessions">Accessing User Sessions</h2><p>Right now, our dashboard just shows static text. We need to make it smart so it displays the actual user&rsquo;s name and email.</p><p>To do this, we use the <code>useSession</code> hook from the <code>auth-client</code>. This hook gives us real-time access to the user&rsquo;s data.</p><p>Update your <code>app/dashboard/page.tsx</code> file with the following:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token comment">//app/dashboard/page.tsx</span>
<span class="token string">"use client"</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span> authClient <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/lib/auth-client"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"next/navigation"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Dashboard</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token function">useRouter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> data<span class="token punctuation">:</span> session<span class="token punctuation">,</span> isPending <span class="token punctuation">}</span> <span class="token operator">=</span> authClient<span class="token punctuation">.</span><span class="token function">useSession</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>isPending<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex min-h-screen items-center justify-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>p</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-gray-500<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Loading<span class="token operator">...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><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">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>session<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">"/signin"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col items-center justify-center min-h-screen gap-4 bg-white text-black<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">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-2xl font-bold<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Welcome back<span class="token punctuation">,</span> <span class="token punctuation">{</span>session<span class="token punctuation">.</span>user<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token operator">!</span><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 attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-gray-600<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        You are logged <span class="token keyword">in</span> <span class="token keyword">as</span><span class="token punctuation">{</span><span class="token string">" "</span><span class="token punctuation">}</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>font-semibold<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>session<span class="token punctuation">.</span>user<span class="token punctuation">.</span>email<span class="token punctuation">}</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>p</span><span class="token punctuation">&gt;</span></span>

      <span class="token operator">&lt;</span>button
        onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token keyword">await</span> authClient<span class="token punctuation">.</span><span class="token function">signOut</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
            fetchOptions<span class="token punctuation">:</span> <span class="token punctuation">{</span>
              onSuccess<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
                router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">"/signin"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
              <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">}</span>
        className<span class="token operator">=</span><span class="token string">"px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600 transition"</span>
      <span class="token operator">&gt;</span>
        Sign Out
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>We introduced the <code>useSession()</code> hook. This is the bridge between the frontend and the user&rsquo;s session. It gives us access to the current session and keeps it in sync as authentication changes. It returns two key values:</p><ul><li><strong>data</strong>: The session object containing user information (or null if not logged in).</li><li><strong>isPending</strong>: A boolean indicating whether the session is still loading. With this, we&rsquo;re able to show a loading state so the user doesn&rsquo;t see empty content.</li></ul><p>Finally, the Sign Out button calls <code>authClient.signOut()</code>. This function invalidates the session cookie and uses the <code>onSuccess</code> callback to send the user straight back to the login screen.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/authenticated-user-session.gif?sfvrsn=cf86529c_2" title="Displaying the authenticated user&#39;s session data" alt="Displaying the authenticated user&#39;s session data" /></p><h2 id="session-management-and-protected-routes">Session Management and Protected Routes</h2><p>Now that our app works, let&rsquo;s look at what happens under the hood.</p><p>When a user signs in, Better Auth creates a session and stores it as an HttpOnly cookie. Unlike regular cookies that you can read with <code>document.cookie</code>, these are blocked from frontend JavaScript entirely. Only the browser can send them automatically with each request to the server.</p><p>There are two main ways of securing your pages, and they serve different purposes:</p><ul><li><strong>Client-Side Protection</strong>: This is what we implemented in our <code>app/dashboard/page.tsx</code> earlier. We wait for the session to load in the browser, and, if it&rsquo;s missing, we redirect the user to the &ldquo;Sign In&rdquo; page.</li><li><strong>Server-Side Protection (better for security)</strong>: We check the session on the server before the page renders. If there&rsquo;s no valid session, the request gets blocked immediately, and the sensitive page content is never sent to the browser.</li></ul><p>To implement server-side protection, we use middleware. Middleware is code that runs before a page loads. It sits between the user&rsquo;s request and your page, checking conditions and deciding whether to allow access or redirect elsewhere. In Next.js, it runs on the server, so unauthorized users never even download the page.</p><h2 id="protecting-routes-with-middleware">Protecting Routes with Middleware</h2><p>Create a new file named <code>middleware.ts</code> at the same level as your app folder and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token comment">//middleware.ts</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> betterFetch <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@better-fetch/fetch"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> Session <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"better-auth/types"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> NextResponse<span class="token punctuation">,</span> <span class="token keyword">type</span> NextRequest <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"next/server"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">authMiddleware</span><span class="token punctuation">(</span>request<span class="token punctuation">:</span> NextRequest<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> data<span class="token punctuation">:</span> session <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> betterFetch<span class="token operator">&lt;</span>Session<span class="token operator">&gt;</span><span class="token punctuation">(</span>
    <span class="token string">"/api/auth/get-session"</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      baseURL<span class="token punctuation">:</span> request<span class="token punctuation">.</span>nextUrl<span class="token punctuation">.</span>origin<span class="token punctuation">,</span>
      headers<span class="token punctuation">:</span> <span class="token punctuation">{</span>
        cookie<span class="token punctuation">:</span> request<span class="token punctuation">.</span>headers<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">"cookie"</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token string">""</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span>
  <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>session<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> NextResponse<span class="token punctuation">.</span><span class="token function">redirect</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">URL</span><span class="token punctuation">(</span><span class="token string">"/signin"</span><span class="token punctuation">,</span> request<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> NextResponse<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">export</span> <span class="token keyword">const</span> config <span class="token operator">=</span> <span class="token punctuation">{</span>
  matcher<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"/dashboard"</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 a nutshell, the config object at the bottom defines the rules of engagement, telling Next.js to strictly apply this security check only to routes starting with <code>/dashboard</code>. When a user attempts to visit the page, the middleware steps in to verify their session first. If the session is missing, it instantly blocks the request and redirects them to the &ldquo;Sign In&rdquo; page, preventing the protected content from reaching the browser.</p><h2 id="refactor-the-dashboard">Refactor the Dashboard</h2><p>Now that the server (middleware) is handling the security, we can simplify our dashboard page. We don&rsquo;t need to redirect from inside the component anymore, but we&rsquo;ll keep the data fetching to show the user&rsquo;s name and email address.</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token comment">//app/dashboard/page.tsx</span>
<span class="token string">"use client"</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span> authClient <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/lib/auth-client"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"next/navigation"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Dashboard</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token function">useRouter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> data<span class="token punctuation">:</span> session<span class="token punctuation">,</span> isPending <span class="token punctuation">}</span> <span class="token operator">=</span> authClient<span class="token punctuation">.</span><span class="token function">useSession</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>isPending<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex min-h-screen items-center justify-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>p</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-gray-500<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Loading<span class="token operator">...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><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">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col items-center justify-center min-h-screen gap-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>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-2xl font-bold<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Dashboard<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>p-4 border rounded shadow-sm bg-white min-w-[300px]<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">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-gray-600 mb-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          Signed <span class="token keyword">in</span> <span class="token keyword">as</span><span class="token punctuation">:</span><span class="token punctuation">{</span><span class="token string">" "</span><span class="token punctuation">}</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>font-semibold text-black<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token punctuation">{</span>session<span class="token operator">?</span><span class="token punctuation">.</span>user<span class="token punctuation">.</span>email<span class="token punctuation">}</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>p</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-xs text-gray-400<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>User ID<span class="token punctuation">:</span> <span class="token punctuation">{</span>session<span class="token operator">?</span><span class="token punctuation">.</span>user<span class="token punctuation">.</span>id<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

      <span class="token operator">&lt;</span>button
        onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token keyword">await</span> authClient<span class="token punctuation">.</span><span class="token function">signOut</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
            fetchOptions<span class="token punctuation">:</span> <span class="token punctuation">{</span>
              onSuccess<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
                router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">"/signin"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
              <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">}</span>
        className<span class="token operator">=</span><span class="token string">"px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600 transition"</span>
      <span class="token operator">&gt;</span>
        Sign Out
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Now when we sign out from the app and try to manually visit <a target="_blank" href="http://localhost:3000/dashboard">http://localhost:3000/dashboard</a>, we should be instantly redirected back to the sign-in page. The dashboard will never attempt to render because there&rsquo;s no valid session.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/access-the-dashboard.gif?sfvrsn=32489ceb_2" title="Trying to access the dashboard without a session" alt="Trying to access the dashboard without a session" /></p><h2 id="conclusion">Conclusion</h2><p>At the base level, Better Auth handles the heavy lifting for authentication. The good thing is you aren&rsquo;t reinventing the wheel, and because it works with pretty much everything, you don&rsquo;t even have to rewrite your whole auth setup if you switch frameworks down the line. It just works, so you can focus on your app.</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">An Introduction to TanStack DB: A Reactive Data Layer for Modern Web Applications</h4></div><div class="col-8"><p class="u-fs16 u-mb0">In this article, we will build a to-do app to <a target="_blank" href="https://www.telerik.com https://www.telerik.com/blogs/introduction-tanstack-db-reactive-data-layer-modern-web-applications">see TanStack DB in action</a>. We&rsquo;ll cover how to set up collections, what &ldquo;live queries&rdquo; are, and why &ldquo;differential dataflow&rdquo; makes it so fast. We'll also cover when to use TanStack DB and when TanStack Query alone is enough.</p></div></div></aside><img src="https://feeds.telerik.com/link/10827/17316560.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-04-18T12:15:37Z</updated>
    <author>
      <name>Hassan Djirdeh </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17315937/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/10827/17315937.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:aa64f913-fece-4c56-bbb5-5397e3128e02</id>
    <title type="text">What We’ve Learned Designing Dev Tools in the Age of AI</title>
    <summary type="text">AI didn’t just change how we write code. It changed how we build products. See what four lessons Progress Telerik and Kendo UI engineering and product teams have learned.</summary>
    <published>2026-04-08T16:13:28Z</published>
    <updated>2026-04-18T12:15:37Z</updated>
    <author>
      <name>Alyssa Nicoll </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17315927/what-weve-learned-designing-dev-tools-ai"/>
    <content type="text"><![CDATA[<p><span class="featured">AI didn&rsquo;t just change how we write code. It changed how we build products.</span></p><p>Over the last year, AI coding agents have gone from glorified autocomplete to autonomous systems capable of scaffolding entire features.</p><p>As our VP of Product put it:</p><blockquote><p>&ldquo;The speed of software engineering is no longer the bottleneck.&rdquo;<br />&mdash; Genady Sergeev, VP Product, Progress</p></blockquote><p>If that&rsquo;s true&mdash;and it increasingly feels like it is&mdash;then something fundamental has shifted.</p><p>The constraint isn&rsquo;t typing. It&rsquo;s judgment.</p><p>These lessons come directly from conversations with our engineering and product teams. Across many of interviews and internal reflections, four themes emerged.</p><h2 id="lesson-1-ai-is-best-at-getting-us-started">Lesson #1: AI Is Best at Getting Us Started</h2><p>One of our product leads described the shift this way:</p><blockquote><p>&ldquo;AI made refactoring and handling technical debt much faster, allowing us to focus on market features. Validating ideas, creating POCs and writing tests are also areas where we&rsquo;ve seen huge impact. The whole development lifecycle changed, and it opened the door for exploration and innovation.&rdquo;<br />&mdash; Yoana Kalaydzhieva, Senior Manager, Software Engineering, Progress</p></blockquote><p>AI lowers the cost of starting. It accelerates refactoring. It scaffolds tests. It makes proof-of-concepts nearly frictionless.</p><p>But our engineers were equally honest:</p><blockquote><p>&ldquo;AI is better at starting than finishing.&rdquo;<br />&mdash; Stefan Mariyanov, Senior Product Manager, Progress</p></blockquote><p>AI gives you momentum. It doesn&rsquo;t give you judgment.</p><p>What we realized is that developers don&rsquo;t actually want magic answers&mdash;they want orientation. They want something to react to, refine and push against.</p><p>That changed how we thought about AI in our tools. Instead of &ldquo;generate and disappear,&rdquo; we moved toward:</p><ul><li>Iterative workflows</li><li>Clear stopping points</li><li>Explicit human decision moments</li></ul><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/what-ai-unlocks.png?sfvrsn=7ccd81b4_2" alt="What AI unlocks: refactoring, tech debt, POCs, tests, exploration" /></p><p>AI made refactoring and technical debt much faster, allowing teams to focus on market features. Validating ideas, creating POCs and writing tests also saw huge impact.</p><p>And what that really opened up was <em>exploration</em>.</p><h2 id="lesson-2-clever-≠-correct">Lesson #2: Clever &ne; Correct</h2><p>Then we ran into something humbling.</p><p>AI-generated code often looks clean, structured and convincing. The formatting is good. The structure feels familiar. The solution appears reasonable at first glance. But many times it&rsquo;s simply wrong.</p><p>As one of our engineers put it:</p><blockquote><p>&ldquo;Code often looks right but breaks in subtle ways.&rdquo;<br />&mdash; Stefan Mariyanov, Senior Product Manager, Progress</p></blockquote><p>That&rsquo;s the danger. It sounds right.</p><p>Kathryn Grayson Nanz framed this beautifully:</p><blockquote><p>&ldquo;I&rsquo;d encourage teams to learn how AI actually works instead of treating it like a black box. Even a high-level understanding&mdash;how models predict the next word, how they gain context&mdash;demystifies the magic.&rdquo;<br />&mdash; Kathryn Grayson Nanz, Senior Developer Advocate, Progress</p></blockquote><p>The key thing to understand is that AI doesn&rsquo;t understand truth. It predicts plausibility. It generates the next token based on patterns it has learned.</p><p>And when tools are confidently wrong, trust erodes fast.</p><p>For developer tools, that&rsquo;s a serious problem. Developers rely on their tools to accelerate their work, not introduce hidden uncertainty. If AI suggestions consistently require double-checking or rewriting, the productivity gains disappear.</p><p>That realization forced us to rethink how AI should be integrated into the products we build.</p><p>Instead of asking AI to guess what developers might want, we started focusing on giving it better context. Rather than generating output in isolation, we began connecting AI directly to the frameworks, component libraries and development tools our users already rely on.</p><p>This is where things like our MCP server and product-aware AI tooling come in. By allowing assistants to access real project structure, real component APIs and real framework constraints, the output becomes grounded in the actual environment the developer is working in.</p><p>In other words, the goal isn&rsquo;t to make AI more clever. The goal is to make it more reliable.</p><h3 id="what-this-changed-for-us">What This Changed for Us</h3><p>For instance, in the Progress Kendo UI for <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools">Angular library AI tools</a>, that meant building <strong>product-aware AI</strong> that understands the capabilities and APIs of the components in our libraries. It meant adding <strong>framework-aware constraints</strong> so generated code follows Angular patterns instead of generic JavaScript assumptions (or even outdate Angular patterns). And it meant leaning into <strong>opinionated scaffolding</strong>, where AI helps developers start with valid structures instead of forcing them to repair generated output afterward.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/what-this-changed-for-us.png?sfvrsn=4f624aa8_2" alt="What this changed for us: product-aware AI, framework-aware constraints, opinionated scaffolding better than open-ended guessing. Context beats clevernesss." /></p><p>What we realized is that the gap wasn&rsquo;t intelligence, it was context. AI could generate something that looked clever, but without grounding in real tools and constraints, it still left developers doing the hard part.</p><p>So we shifted the question. Instead of asking how to make AI more impressive, we started asking how to make it more trustworthy. And once we framed it that way, the answer showed up everywhere: context beats cleverness.</p><h2 id="lesson-3-fast-isn’t-free">Lesson #3: Fast Isn&rsquo;t Free</h2><p>Speed came with a cost.</p><p>As we started integrating AI more deeply into developer workflows, we began to see both the upside and the tradeoffs more clearly. The productivity gains were real, but so were the risks.</p><p>One of our VPs of Product reflected on this directly:</p><blockquote><p>&ldquo;Using CLI agents successfully requires certain skills and practice. The improvement rate is so fast that observations from 3&ndash;4 months ago are already outdated.&rdquo;<br />&mdash; Genady Sergeev, VP Product, Progress</p></blockquote><p>That pace of change creates a new kind of pressure. Not just to adopt AI, but to continuously relearn how to use it well.</p><p>And we observed something else happening inside teams.</p><blockquote><p>&ldquo;AI helps experienced developers master their productivity&mdash;it&rsquo;s impressive. But less experienced developers might over-trust AI-generated code, which leads to pull requests that require much deeper senior review.&rdquo;<br />&mdash; Yoana Kalaydzhieva, Senior Manager, Software Engineering, Progress</p></blockquote><p>In other words, AI doesn&rsquo;t just accelerate output. It amplifies behavior.</p><p>For experienced developers, that can mean faster iteration and deeper focus. For less experienced developers, it can mean moving quickly in the wrong direction&mdash;and creating more work downstream.</p><p>That&rsquo;s when the real cost of speed started to show up. AI makes output cheaper, but not ownership. It accelerates mistakes just as efficiently as it accelerates success. And when everything moves faster, the cost of catching issues later increases. So we changed how we approached tooling.</p><p>Instead of optimizing purely for generation speed, we started designing for <strong>accountability alongside acceleration</strong>. That meant introducing clear checkpoints where human review is expected, giving teams control over the models and endpoints they use, and enabling every AI-generated action to be traced, inspected and understood.</p><p>We also shifted our mindset around AI output itself. Instead of treating it as a near-final draft, we began treating it as <strong>untrusted input</strong>&mdash;something useful, but something that still requires validation.</p><h3 id="demo-highlight-observability-as-accountability">Demo Highlight: Observability as Accountability</h3><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/ai-observability-program.png?sfvrsn=1cc9aa2c_2" alt="Join the Progress AI Observability Platform Early Access Program" /></p><p>This is where our <a target="_blank" href="https://www.telerik.com/ai-observability-platform">AI Observability Platform</a> became part of the solution. Not to &ldquo;watch code,&rdquo; but to watch reasoning.</p><p>We wanted to make it possible to see what the model did, how it arrived at a result and why certain decisions were made along the way. Because if AI is going to operate inside real workflows, its behavior can&rsquo;t be opaque. Visibility becomes a requirement, not a bonus.</p><p>If AI accelerates execution, then visibility has to scale with it. Because speed, on its own, isn&rsquo;t the goal. Speed is only valuable when accountability scales alongside it.</p><h2 id="lesson-4-ai-belongs-in-the-product—thoughtfully">Lesson #4: AI Belongs in the Product&mdash;Thoughtfully</h2><p>This one surprised us most.</p><p>One internal reflection stood out:</p><blockquote><p>&ldquo;What surprised me most is how quickly the attention span of our customers dropped, and how much the evaluation process changed.&rdquo;<br />&mdash; Yoana Kalaydzhieva, Senior Manager, Software Engineering, Progress</p></blockquote><p>Evaluation cycles compressed, tolerance for friction disappeared, and that shift affects end users too. Users struggle with:</p><ul><li>Complex data</li><li>Dense interfaces</li><li>Discoverability</li></ul><p>AI isn&rsquo;t a replacement UI. It&rsquo;s an augmentation layer.</p><h3 id="demo-highlight-ai-inside-the-interface">Demo Highlight: AI Inside the Interface</h3><p>Lesson #4 shows up very clearly in how we&rsquo;ve approached AI within the Kendo UI Grid&mdash;not as a replacement for the interface, but as a layer that makes it easier to use.</p><p>Instead of hiding the system behind a prompt box, we&rsquo;ve focused on keeping the structure intact: columns, grouping, filtering and data visibility all remain explicit and inspectable. AI becomes a way to express intent faster&mdash;&ldquo;group by this,&rdquo; &ldquo;filter that&rdquo;&mdash;while still grounding every action in the underlying UI. You can explore the full capabilities here: <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/grid/smart-grid">Angular Smart Grid</a>.</p><p>What this means in practice is that the grid doesn&rsquo;t disappear when AI is introduced&mdash;it becomes more approachable. Users can move faster without losing their bearings, because every change is visible, reversible and tied to real UI controls.</p><p>That balance is the point: reducing cognitive load without sacrificing control. Rather than asking users to trust a black box, the grid invites them to collaborate with it&mdash;AI helps initiate actions, but the interface remains the source of truth.</p><h2 id="what-we’re-really-learning">What We&rsquo;re Really Learning</h2><p>Over time, these lessons started to feel less like separate observations and more like different edges of the same shape. AI is incredibly effective at helping us begin, but it doesn&rsquo;t carry the responsibility of finishing. It can produce outputs that look convincing, but without context, that confidence can be misplaced. And while it dramatically increases speed, it also raises the cost of mistakes when that speed isn&rsquo;t paired with visibility and accountability.</p><p>Even when we bring AI into the product itself, the goal isn&rsquo;t to replace the interface&mdash;it&rsquo;s to make it easier to use without taking control away from the user.</p><p>What this ultimately points to is a deeper shift in how we think about building tools. AI changes how quickly we can move, but it doesn&rsquo;t change who owns the outcome. Developers still make the decisions. Teams still carry the consequences. So the goal can&rsquo;t just be faster output&mdash;it has to be confidence in what we&rsquo;re building, even as everything around us accelerates.</p><h2 id="let’s-talk-about-it">Let&rsquo;s Talk About It</h2><p>We&rsquo;re hosting a live <strong>Developer Roundtable</strong> on <strong>April 15 at 9 a.m. PT</strong>, where we&rsquo;re unpacking all of this in real time&mdash;no slides, no polished answers, just honest conversation with developers in the trenches.</p><p>We&rsquo;ll be digging into questions like:</p><ul><li>Where has AI actually helped you move faster&mdash;and where has it created more work?</li><li>How are you validating AI-generated code today?</li><li>What guardrails feel necessary right now?</li><li>Where has AI in tools felt genuinely helpful &hellip; and where has it felt forced?</li></ul><p>Join us on the Progress Labs Discord:</p><p><a target="_blank" href="https://discord.gg/bUhBHmz6?event=1479492929411092562"> Come share what&rsquo;s working, what&rsquo;s breaking and what still feels unresolved.</a></p><p>Because the truth is&mdash;we&rsquo;re all still figuring this out. And the best insights aren&rsquo;t coming from headlines. They&rsquo;re coming from conversations like this.</p><img src="https://feeds.telerik.com/link/10827/17315927.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:260a4048-454d-49d1-adbc-60f4cc32775d</id>
    <title type="text">Workflows in the Age of AI: How Design &amp; Development Workflows Changed in 2025—and What Comes Next</title>
    <summary type="text">We asked 200+ respondents across design and development about the ways they’re leveraging new AI capabilities in their work. Download the full report and check out these top takeaways.</summary>
    <published>2026-04-07T19:31:29Z</published>
    <updated>2026-04-18T12:15:37Z</updated>
    <author>
      <name>Kathryn Grayson Nanz </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17315391/workflows-age-ai-how-design-development-changed-what-comes-next"/>
    <content type="text"><![CDATA[<p><span class="featured">We asked 200+ respondents across design and development about the ways they&rsquo;re leveraging new AI capabilities in their work. Download the full report and check out these top takeaways.</span></p><p>AI may be a normal part of daily life now, but the reality of implementing AI-powered tooling in the workplace is not so simple. Teams are moving faster, but workflows are becoming messier, more complex and more challenging to scale. AI is improving productivity at the individual and small-team level&mdash;but those gains aren't necessarily translating into consistent, scalable workflows across teams.</p><p>How do we know? <a target="_blank" href="https://www.telerik.com/blogs/designer-developer-collaboration-age-ai">In our 2025 Designer-Developer Collaboration survey</a>, we asked 200+ respondents across design and development (including hybrid and leadership roles, as well) about the ways they&rsquo;re leveraging new AI capabilities in their work. You can <a target="_blank" href="https://www.telerik.com/ai-design-development-workflows-report-2025">download the full report</a> to see everything, but these were our top takeaways:</p><h2 id="-1-ai-is-the-default-maturity-is-not-">1. AI Is the Default&mdash;Maturity Is Not.</h2><p>People are using AI: 84% of people, to be precise (or at least, 84% of the people who filled out our survey). This was divided among folks who are all in&mdash;taking &ldquo;an AI-first approach across [their] entire process&rdquo;&mdash;and folks who have AI tools regularly integrated or in experimental phases in their current workflows. Only 16% said they were avoiding the use of AI tools entirely.</p><p>The challenge is no longer simply adoption, but rather how to turn AI usage into a reliable, repeatable process.</p><h2 id="-2-speed-is-real-trust-is-conditional-">2. Speed Is Real. Trust Is Conditional.</h2><p>There&rsquo;s a lot of back-and-forth right now on whether AI <em>actually</em> delivers its promises of improved productivity. </p><p>Our respondents were also mixed; a little over half said it was &ldquo;moderately positive&rdquo;, helping somewhat but with some limitations. And 33% found it to have a negative effect&mdash;split between being neutral (having no impact), moderately negative (added more work than saved), or significantly negative (disrupted workflow significantly). Only 16% felt strongly positive about it, claiming major time savings and quality improvements.</p><p>Speed isn&rsquo;t an issue, but consistency is. We need tools and systems that can be trusted to produce reliable results in order to scale them across teams and businesses.</p><h2 id="-3-collaboration-friction-still-matters-">3. Collaboration Friction Still Matters</h2><p>Despite all the new tooling AI has made available to us in the form of quick prototyping, design-to-code features and vibe coding &hellip; it hasn&rsquo;t fixed the core design-dev &ldquo;handoff&rdquo; problem. </p><p>Only 21% of our participants reported &ldquo;smooth handoffs and minimal issues&rdquo; when we asked how they would rate the efficiency of the design implementation process. When things fall through the cracks, slower time-to-market (42%), rework (33%) and wasted time (36%) were listed as the top three consequences&mdash;all significant pain points at a time when we&rsquo;re shipping new products and features faster than ever before.</p><p>This is where structured systems, shared standards and better-integrated tooling become critical.</p><h2 id="-4-2026-is-about-operational-execution-not-experimentation-">4. 2026 Is About Operational Execution&mdash;Not Experimentation</h2><p>People&rsquo;s top priority coming into 2026 was the effective implementation of AI tools (39%), closely followed by building hybrid skillsets across their teams (29%). AI is reshaping the workplace, and both teams and individual roles are stretching to incorporate the disruption and turn it into something valuable. </p><p>This shift makes the path forward clear: AI needs to move from ad-hoc usage into systems, standards-aware workflows and production-ready processes that can scale. Whether or not that&rsquo;s possible is something I suppose we&rsquo;ll have to wait until next year&rsquo;s survey to find out!</p><h2 id="-want-the-full-picture-">Want the Full Picture?</h2><p>You can <a target="_blank" href="https://www.telerik.com/ai-design-development-workflows-report-2025">download the full report</a> to see the answers to all the questions, including extra data analysis and interesting cross-sections. We think there&rsquo;s a lot to learn, and the report is packed with helpful tips&mdash;as well as our own predictions on what to watch next.</p><p>Finally, if you took the survey: <strong>thank you so much!</strong> We genuinely enjoyed going through all the responses and seeing what everyone had to say. Keep an eye out for next year&rsquo;s survey, and&mdash;until then&mdash;keep building and experimenting. We can&rsquo;t wait to see what you&rsquo;ve been working on!</p><p><a class="Btn" target="_blank" href="https://www.telerik.com/ai-design-development-workflows-report-2025">See Full Report</a></p><img src="https://feeds.telerik.com/link/10827/17315391.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-04-18T12:15:37Z</updated>
    <author>
      <name>Claudio Bernasconi </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17314706/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/10827/17314706.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:8adaf186-7275-4dfe-8fbd-0e63950051ac</id>
    <title type="text">Build Accessible Components with Angular Aria</title>
    <summary type="text">A simple way to add accessibility to your Angular app is with Angular Aria, which gives you production-ready, WCAG-compliant directives. Take a look.</summary>
    <published>2026-04-01T19:25:26Z</published>
    <updated>2026-04-18T12:15:37Z</updated>
    <author>
      <name>Dany Paredes </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17311874/build-accessible-components-angular-aria"/>
    <content type="text"><![CDATA[<p><span class="featured">A simple way to add accessibility to your Angular app is with Angular Aria, which gives you production-ready, WCAG-compliant directives.</span></p><p>Building accessible components is one of those things we know we <em>should</em> do, but often skip because it feels overwhelming. We need to <a target="_blank" href="https://www.telerik.com/blogs/improving-navigation-accessibility-4-quick-tips">read about accessibility tips and tricks</a> and a lot of documentation.</p><p>You start with a simple dropdown menu, knowing you need to handle keyboard navigation, ARIA attributes, focus management and screen reader support. Before you know it, your &ldquo;simple&rdquo; component has 200 lines of accessibility code you&rsquo;re not even sure is correct. (Unless you&rsquo;re using the Progress Kendo UI for <a target="_blank" href="https://www.telerik.com/kendo-angular-ui">Angular library</a>, which has accessibility baked in for you. )</p><p>What if I told you there&rsquo;s a way to get the accessibility magic you need, regardless of component library, with full control over your styling with the magic of <a target="_blank" href="https://angular.dev/guide/aria/overview">Angular Aria</a>?</p><p>But what is Angular Aria? Let&rsquo;s make a small intro.</p><h2 id="what-is-angular-aria">What Is Angular Aria?</h2><p>Think of Angular Aria as a collection of accessibility superpowers for your components, but instead of manually implementing keyboard navigation, ARIA attributes and focus management, you import a directive, add it to your HTML and, boom, your component is accessible.</p><p>The Angular team built these directives following the <a target="_blank" href="https://www.w3.org/WAI/ARIA/apg/">W3C Accessibility Guidelines</a>, so you don&rsquo;t have to become an accessibility expert to build compliant components.</p><h2 id="hold-on-what-about-angular-material">Hold On, What About Angular Material?</h2><p>Great question! If you&rsquo;ve been using Angular for a while, you&rsquo;re probably thinking: <em>&ldquo;We already have <a target="_blank" href="https://material.angular.io/">Angular Material</a>. Why do we need another library?&rdquo;</em></p><p>Here are the key differences:</p><p>Angular Material gives you complete, prestyled components. They look great out of the box, but they come with Material Design opinions baked in. If you want a button that doesn&rsquo;t look like a Material button, you&rsquo;re going to fight the framework.</p><p>Angular Aria gives you headless directives&mdash;just the accessibility logic, zero styling. You get all the keyboard navigation, ARIA attributes and screen reader support, but you control every pixel of how it looks.</p><p>Think of it this way:</p><ul><li>Angular Material: It is plug and play, looks good, works immediately, but everyone has the same result. If you were building a physical doorway to your business, it would look like all other businesses, just with your business name on the sign.</li><li>Angular Aria: This tool is more like the ramp to your front door, enabling anyone to access the business entrance, while allowing you to choose the awning, the window display and the door color.</li></ul><p>So when should you use each one? We&rsquo;ll dive deeper into that later in the article, but here&rsquo;s the quick answer:</p><ul><li>Use <strong>Angular Material</strong> when you need to ship fast and Material Design works for you.</li><li>Use <strong>Angular Aria</strong> when you have custom design requirements and need full control.</li></ul><p>Remember, accessibility isn&rsquo;t optional anymore. It&rsquo;s a <a target="_blank" href="https://www.telerik.com/blogs/what-does-european-accessibility-act-mean-developers">legal requirement</a> in many countries, and, more importantly, it&rsquo;s the right thing to do.</p><p>But implementing accessibility correctly is <strong>hard</strong>. You need to know:</p><ul><li>Which ARIA attributes to use (and when)</li><li>How keyboard navigation should work for each pattern</li><li>How to manage focus properly</li><li>How screen readers interpret your markup</li></ul><p>Angular Aria handles this complexity for you. You focus on the HTML structure, CSS styling and business logic, and Angular Aria takes care of accessibility.</p><p>But, as always, the best way to learn is by building something. Let&rsquo;s do it!</p><h2 id="set-up-the-project">Set Up the Project</h2><p>First, create a new Angular application. In your terminal, run the following command (be sure to have Node.js installed).</p><pre class=" language-bash"><code class="prism  language-bash">npx @angular/cli@latest new angular-aria-demo
</code></pre><p>When CLI prompts stylesheet format, pick CSS.</p><pre class=" language-bash"><code class="prism  language-bash">  - **Which stylesheet <span class="token function">format</span> would you like to use?** &rarr; CSS
</code></pre><p>Now, navigate to your project and add Angular Aria:</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">cd</span> angular-aria-demo
<span class="token function">npm</span> <span class="token function">install</span> @angular/aria
</code></pre><p>That&rsquo;s it. We now have a fresh Angular project with Angular Aria installed. Let&rsquo;s build something accessible!</p><h2 id="building-an-accessible-toolbar">Building an Accessible Toolbar</h2><p>Let&rsquo;s build a text formatting toolbar, the kind you see in rich text editors. This is a perfect example because it looks simple but has surprising accessibility complexity.</p><p>Using the CLI, generate a new component editor-toolbar:</p><pre class=" language-bash"><code class="prism  language-bash">ng generate c components/editor-toolbar
</code></pre><p>Perfect! Open the component with your editor, and import <code>Toolbar</code>, <code>ToolbarWidget</code> and <code>ToolbarWidgetGroup</code> directives provided by <code>@angular/aria/toolbar</code>.</p><pre class=" language-typescript"><code class="prism  language-typescript">  <span class="token keyword">import</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
  <span class="token keyword">import</span> <span class="token punctuation">{</span> Toolbar<span class="token punctuation">,</span> ToolbarWidget<span class="token punctuation">,</span> ToolbarWidgetGroup <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/aria/toolbar'</span><span class="token punctuation">;</span>
  
  @<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    selector<span class="token punctuation">:</span> <span class="token string">'app-editor-toolbar'</span><span class="token punctuation">,</span>
    templateUrl<span class="token punctuation">:</span> <span class="token string">'./editor-toolbar.component.html'</span><span class="token punctuation">,</span>
    styleUrl<span class="token punctuation">:</span> <span class="token string">'./editor-toolbar.component.css'</span><span class="token punctuation">,</span>
    imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>Toolbar<span class="token punctuation">,</span> ToolbarWidget<span class="token punctuation">,</span> ToolbarWidgetGroup<span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">EditorToolbarComponent</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre><p>Now it&rsquo;s time to build the HTML structure. We create a div container with the directive <code>[ngToolbar]</code>, which works as the main container. We also need <code>ToolbarWidget</code> to use with individual buttons and <code>ToolbarWidgetGroup</code> for groups of related buttons.</p><p>In the following HTML, we use every directive with divs and button elements. Copy it and paste into the <code>editor-toolbar.html</code>.</p><pre class=" language-html"><code class="prism  language-html">  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">ngToolbar</span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Text Formatting Tools<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>group<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">ngToolbarWidget</span>
           <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>undo<span class="token punctuation">"</span></span>
           <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span>
           <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>undo<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     Undo
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">ngToolbarWidget</span>
           <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>redo<span class="token punctuation">"</span></span>
           <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span>
           <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>redo<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     Redo
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

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

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

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

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

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

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

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

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

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

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

Watch mode enabled. Watching <span class="token keyword">for</span> <span class="token function">file</span> changes<span class="token punctuation">..</span>.
NOTE: Raw <span class="token function">file</span> sizes <span class="token keyword">do</span> not reflect development server per-request transformations.
  ➜  Local:   http://localhost:4200/
  ➜  press h + enter to show <span class="token function">help</span>
</code></pre><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/keyboard-navigating-buttons.gif?sfvrsn=b37b8cd8_8" alt="User navigates buttons with keyboard arrow keys" /></p><p>Try to use your toolbar with your keyboard. You&rsquo;ll find it works, and we didn&rsquo;t have to write any code for keyboard navigation logic (like: Arrow keys, Home, End), focus management, ARIA role attributes, screen reader announcements or selection state management. All of that complexity? Gone.</p><p>The <code>ngToolbar</code>, <code>ngToolbarWidget</code> and <code>ngToolbarWidgetGroup</code> directives handle all of that automatically.</p><p>We now have a fully accessible toolbar that works with keyboard navigation and screen readers, and we only wrote the HTML structure and CSS.</p><p>Angular Aria provides directives for the most common interactive patterns, we can get components for search and selection (like Autocomplete, Listbox and Select), navigation and actions (Menu, Menubar and Toolbar like we just built), and content organization (Accordion, Tabs, Tree and Grid). Every directive comes with complete documentation, working examples and API references. You can see the <a target="_blank" href="https://angular.dev/guide/aria/overview#whats-included">full list of available components</a> in the official Angular Aria documentation.</p><h2 id="but-im-a-fan-of-angular-material">But I&rsquo;m a Fan of Angular Material</h2><p>Yes, I understand Angular Material has a long relationship with Angular devs. You can continue using Angular Material when you:</p><ol><li><strong>Need to ship fast</strong> &ndash; You&rsquo;re building an MVP or internal tool and don&rsquo;t want to spend time on custom styling.</li><li><strong>Like Material Design</strong> &ndash; You&rsquo;re OK with the Google Material Design aesthetic.</li><li><strong>Have limited design resources</strong> &ndash; Your team doesn&rsquo;t have dedicated designers.</li></ol><p>Remember, <a target="_blank" href="https://material.angular.io/">Angular Material</a> is amazing, but it comes with opinions about how things should look.</p><p>If you try to heavily customize Material components, you&rsquo;ll spend more time fighting the framework than building features. I&rsquo;ve been there&mdash;overriding Material styles with <code>::ng-deep</code> and <code>!important</code> until the CSS becomes unmaintainable.</p><p>And don&rsquo;t even get me started on theming. Creating a custom theme for Angular Material is&hellip; let&rsquo;s just say &ldquo;special.&rdquo; It&rsquo;s doable, but it&rsquo;s tricky and requires deep knowledge of Sass and Material&rsquo;s theming system. (If you&rsquo;re curious about the complexity, I wrote about it in <a target="_blank" href="https://www.telerik.com/blogs/theme-ui-frameworks-angular-part-2-custom-theme-angular-material">Theme UI Frameworks in Angular: Part 2 - Custom Theme for Angular Material</a>.)</p><p>Angular Aria solves this by giving you <strong>zero styles</strong>. You start with a blank canvas and build exactly what you need.</p><p>Remember for simple cases, native elements are already accessible when you use <code>&lt;button&gt;</code> for buttons, <code>&lt;input type="radio"&gt;</code> for radio buttons or <code>&lt;select&gt;</code> for simple dropdowns. But Angular Aria gives you a third option: <strong>headless accessible components</strong> that you can style however you want, we can meet accessibility requirements, maintain full design control and avoid reinventing the wheel.</p><h2 id="recap">Recap</h2><p>We learned that accessibility doesn&rsquo;t have to be overwhelming. Angular Aria gives you production-ready, WCAG-compliant directives that handle the complex parts.</p><p>We provide the HTML structure and CSS and Angular Aria provides the accessibility without pain!</p><h3 id="but-what-about-kendo-ui">But What About Kendo UI?</h3><p>Maybe you want to ship faster (really fast) and have complex scenarios with datalist, charts, schedulers and complex UI patterns. If you read this article and are thinking: <em>&ldquo;This is great, but I still have to write all the HTML and CSS myself. Why not just use a complete component library?&rdquo;</em> you&rsquo;re asking the right question.</p><p>Here&rsquo;s when Progress <strong>Kendo UI for Angular</strong> makes more sense than Angular Aria or Angular Material:</p><p><strong>Use Kendo UI when you want:</strong></p><ol><li><strong>Everything out of the box</strong> &ndash; Prebuilt components with professional styling, themes and accessibility already done</li><li><strong>Advanced features included</strong> &ndash; Things like data grids with sorting/filtering, charts, schedulers and complex UI patterns</li><li><strong>Consistent design system</strong> &ndash; A cohesive look across all components without writing custom CSS</li><li><strong>Enterprise-grade support</strong> &ndash; Professional support, regular updates and guaranteed compatibility</li><li><strong>Speed PLUS customization</strong> &ndash; You need to ship fast <em>and</em> need options to customize (you&rsquo;ll have five fully built theme options plus the ability to tweak those or create your own theme)</li></ol><p>There&rsquo;s no &ldquo;wrong&rdquo; choice&mdash;just different tools for different jobs.</p><p>If you&rsquo;re building internal tools or you like the Kendo UI design system, Kendo UI saves you weeks of work, and, honestly? I can build complex stuff (data grids, schedulers, charts) in minutes, making Kendo UI the right answer for me.</p><p>Plus, you can use the Kendo UI for <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/ai-assistant/getting-started">Angular AI Coding Assistant</a>, an MCP server that automatically scaffolds components for AI agents. Instead of manually writing Kendo UI components, your AI assistant can do it for you. </p><blockquote><p>Want to learn more? Check out my article: <a target="_blank" href="https://www.telerik.com/blogs/angular-kendo-ui-mcp-making-agents-work">
 Angular and Kendo UI MCP: Making Agents Work for You</a></p></blockquote><ul><li><a target="_blank" href="https://github.com/danywalls/angular-aria-example">Source code</a></li><li><a target="_blank" href="https://angular.dev/guide/aria/overview">Angular Aria Documentation</a></li></ul><img src="https://feeds.telerik.com/link/10827/17311874.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:88e4a370-d2a2-4d78-ae1f-86792f7c61e1</id>
    <title type="text">Loading, Accessing and Converting Office and PDF Documents with Telerik Document Processing Libraries</title>
    <summary type="text">Here’s what you need to get started with Telerik Document Processing Libraries to work with PDF, Word and Excel files (and, like any good suite, make all those document types look very much alike).</summary>
    <published>2026-03-31T15:30:52Z</published>
    <updated>2026-04-18T12:15:37Z</updated>
    <author>
      <name>Peter Vogel </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17310586/loading-accessing-converting-office-pdf-documents-telerik-document-processing-libraries"/>
    <content type="text"><![CDATA[<p><span class="featured">Here&rsquo;s what you need to get started with Telerik Document Processing Libraries to work with PDF, Word and Excel files (and, like any good suite, make all those document types look very much alike).</span></p><p>Progress Telerik Document Processing Libraries, in addition to letting you work with a variety of document formats (PDF, DOCX, RTF, HTML, XLSX and more), are an example of the reason you buy into a suite of tools: All the tools bear a &ldquo;family resemblance.&rdquo;</p><p>The ideal scenario, of course, would be for a single tool that made all these document formats look the same. Given the differences in format and functionality between, for example, a PDF, a Microsoft Word (or RTF or HTML) document and an Excel spreadsheet, that&rsquo;s not reasonable (though Progress Telerik has achieved that with DOCX, RTF and HTML documents).</p><p>The good news here is that, with Telerik Document Processing Libraries (DPL), the family resemblance is strong enough that, for <em>all</em> of the document types the library supports, I can show you how to load documents, start the editing process, convert between various document types and save a document in this one post.</p><h2 id="configuring-your-project">Configuring Your Project</h2><p>The sample code in this post was all written using the DPL for Windows libraries (even though I was working in ASP.NET Core&mdash;the more technical name for the version I used is &ldquo;.NET(Target OS: Windows).&rdquo; The suite is <a target="_blank" href="https://docs.telerik.com/devtools/document-processing/introduction#required-references">also available for the .NET Framework</a>.</p><p>To create an ASP.NET Core project that would work with &ldquo;all the documents,&rdquo; I added these NuGet packages to my project:</p><ul><li>To work with PDF files: Telerik.Windows.Documents.Fixed</li><li>To work with DOCX, HTML and RTF files: Telerik.Windows.Documents.Flow</li><li>To work with Excel spreadsheets: Telerik.Windows.Documents.Spreadsheet</li></ul><p>For the Excel spreadsheets, I&rsquo;m only going to work with XLSX files, so I added the Telerik.Windows.Documents.Spreadsheet.FormatProviders.OpenXml package to my project. (If I was going to work with, for example, XLS spreadsheet, then I would have added the Telerik.Documents.Spreadsheet.FormatProviders.Xls package.)</p><h2 id="loading-your-document">Loading Your Document</h2><p>The code to load a document from a file into any of these libraries is very similar:</p><ol><li>Create the appropriate provider.</li><li>Use the .NET<code>File</code> object&rsquo;s <code>OpenRead</code> to create a <code>Stream</code> that points to the file.</li><li>Use the provider&rsquo;s <code>Import</code> method to load the stream into the document object.</li></ol><p>Here, for example, is the code to load a PDF file into a <code>RadFixedDocument</code> object (I used this code in an ASP.NET Core application with documents in my project&rsquo;s wwwroot folder):</p><pre class=" language-csharp"><code class="prism  language-csharp">RadFixedDocument doc<span class="token punctuation">;</span>
PdfFormatProvider prov <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">using</span> <span class="token punctuation">(</span>Stream str <span class="token operator">=</span> File<span class="token punctuation">.</span><span class="token function">OpenRead</span><span class="token punctuation">(</span><span class="token string">@"wwwroot/documents/Priorities.pdf"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    doc <span class="token operator">=</span> prov<span class="token punctuation">.</span><span class="token function">Import</span><span class="token punctuation">(</span>str<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">10</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 here&rsquo;s the code to load a DOCX file into a <code>RadFlowDocument</code>:</p><pre class=" language-c"><code class="prism # language-c">RadFlowDocument doc<span class="token punctuation">;</span>
DocxFormatProvider prov <span class="token operator">=</span> <span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">using</span> <span class="token punctuation">(</span>Stream str <span class="token operator">=</span> File<span class="token punctuation">.</span><span class="token function">OpenRead</span><span class="token punctuation">(</span>@<span class="token string">"wwwroot/documents/Priorities.docx"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    doc <span class="token operator">=</span> prov<span class="token punctuation">.</span><span class="token function">Import</span><span class="token punctuation">(</span>str<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">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>As you can see, the code is identical except for the provider (<code>PdfFormatProvider</code> vs. <code>DocxFormatProvider</code>) and document objects (<code>RadFlowDocument</code> vs. <code>RadFixedDocument</code>).</p><p>Because both RTF and HTML documents load into the same <code>RadFlowDocument</code> object as a DOCX document, only the provider object changes (<code>HtmlFormatProvider</code> or <code>RtfFormatProdiver</code> instead of <code>DocxFormatProvider</code>) when working with those file formats. Here&rsquo;s the code to load an RTF document:</p><pre class=" language-csharp"><code class="prism  language-csharp">RadFlowDocument doc<span class="token punctuation">;</span>
RtfFormatProvider prov <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">using</span> <span class="token punctuation">(</span>Stream str <span class="token operator">=</span> File<span class="token punctuation">.</span><span class="token function">OpenRead</span><span class="token punctuation">(</span><span class="token string">@"wwwroot/documents/Priorities.rtf"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    doc <span class="token operator">=</span> prov<span class="token punctuation">.</span><span class="token function">Import</span><span class="token punctuation">(</span>str<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">10</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 here&rsquo;s the almost identical code to load an HTML file:</p><pre class=" language-csharp"><code class="prism  language-csharp">RadFlowDocument doc<span class="token punctuation">;</span>
HtmlFormatProvider prov <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">using</span> <span class="token punctuation">(</span>Stream str <span class="token operator">=</span> File<span class="token punctuation">.</span><span class="token function">OpenRead</span><span class="token punctuation">(</span><span class="token string">@"wwwroot/documents/Priorities.html"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    doc <span class="token operator">=</span> prov<span class="token punctuation">.</span><span class="token function">Import</span><span class="token punctuation">(</span>str<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">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>The code to load an Excel workbook is also similar to what you&rsquo;ve seen before, just swapping in a new document object (<code>Workbook</code>) and provider (<code>XlsxFormatProvider</code>):</p><pre class=" language-csharp"><code class="prism  language-csharp">Workbook doc<span class="token punctuation">;</span>
XlsxFormatProvider prov <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">using</span> <span class="token punctuation">(</span>Stream str <span class="token operator">=</span> File<span class="token punctuation">.</span><span class="token function">OpenRead</span><span class="token punctuation">(</span><span class="token string">@"wwwroot/documents/priority.xlsx"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    doc <span class="token operator">=</span> prov<span class="token punctuation">.</span><span class="token function">Import</span><span class="token punctuation">(</span>str<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">10</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 note: The Workbook object assumes that you&rsquo;re going to load the <em>whole</em> Excel workbook into memory. For very large workbooks, that may not make sense. For that scenario, you should look at the <a target="_blank" href="https://docs.telerik.com/devtools/document-processing/libraries/radspreadstreamprocessing/overview">SpreadStreamProcessing Library</a>.</p><h2 id="modifying-the-documents">Modifying the Documents</h2><p>Once you&rsquo;ve loaded the documents, you can start working with them. You can often simplify your code by using the <code>RadFixedDocumentEditor</code> with PDF documents or the <code>RadFlowDocumentEditor</code>with Word/RTF/HTML documents. Not surprisingly, the code for creating an editor is almost identical for these two document types: create an editor object and pass the document you want loaded into the editor.</p><p>The code to create an editor for a PDF document looks like this:</p><pre class=" language-csharp"><code class="prism  language-csharp">RadFixedDocumentEditor editor <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">RadFixedDocumentEditor</span><span class="token punctuation">(</span>doc<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The code for Word/RTF/HTML documents looks like this:</p><pre class=" language-csharp"><code class="prism  language-csharp">RadFlowDocumentEditor editor <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">RadFlowDocumentEditor</span><span class="token punctuation">(</span>doc<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>That&rsquo;s not to say that, as you start working with those documents, there aren&rsquo;t going to be differences. These are, after all, very different kinds of documents. Having said that, some functionality does work in a similar way across all the document types.</p><p>If, for example, I want to search a PDF document for the text &ldquo;ASP.NET,&rdquo; I create a <code>TextSearch</code> instance from my document object. I then use the <code>TextSearch</code> object&rsquo;s <code>FindAll</code> method to search for text in my PDF document, passing two things: my search text and a <code>TextSearchOptions</code> object that specifies how I want my search conducted. That <code>FindAll</code> object returns a collection of <code>SearchResult</code> objects that I can loop through.</p><p>Typical code, then, looks like this:</p><pre class=" language-csharp"><code class="prism  language-csharp">TextSearch search <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TextSearch</span><span class="token punctuation">(</span>doc<span class="token punctuation">)</span><span class="token punctuation">;</span>
TextSearchOptions opts <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>
CaseSensitive <span class="token operator">=</span> <span class="token keyword">false</span><span class="token punctuation">,</span>
WholeWordsOnly <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">,</span>
UseRegularExpression <span class="token operator">=</span> <span class="token keyword">true</span>
                                                              <span class="token punctuation">}</span><span class="token punctuation">;</span>

IEnumerable<span class="token operator">&lt;</span>SearchResult<span class="token operator">&gt;</span> items <span class="token operator">=</span> search<span class="token punctuation">.</span><span class="token function">FindAll</span><span class="token punctuation">(</span><span class="token string">"ASP.NET"</span><span class="token punctuation">,</span> opts<span class="token punctuation">)</span><span class="token punctuation">;</span>

Debug<span class="token punctuation">.</span><span class="token function">Print</span><span class="token punctuation">(</span>$<span class="token string">"Found {items.Count()} items."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">foreach</span> <span class="token punctuation">(</span>SearchResult item <span class="token keyword">in</span> items<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    Debug<span class="token punctuation">.</span><span class="token function">Print</span><span class="token punctuation">(</span>$<span class="token string">"Found at {item.Range.StartPosition} "</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    Debug<span class="token punctuation">.</span><span class="token function">Print</span><span class="token punctuation">(</span>$<span class="token string">"Found: {item.Result}"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>The process is almost identical for the <code>RadFlowDocument</code> object, except:</p><ul><li>You call the <code>FindAll</code>method directly from the <code>RadFlowDocumentEditor</code>.</li><li>There isn&rsquo;t a separate options object (though all the search options from the <code>TextSearch</code> object are still available).</li><li>The <code>FindAll</code> method on the editor returns <code>FindResult</code> objects instead of <code>SearchResult</code> objects.</li></ul><p>As a result, the equivalent search code for a DOCX, RTF or HTML document looks like this:</p><pre class=" language-csharp"><code class="prism  language-csharp">RadFlowDocumentEditor editor <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">RadFlowDocumentEditor</span><span class="token punctuation">(</span>doc<span class="token punctuation">)</span><span class="token punctuation">;</span>

IEnumerable<span class="token operator">&lt;</span>FindResult<span class="token operator">&gt;</span> items <span class="token operator">=</span> editor<span class="token punctuation">.</span><span class="token function">FindAll</span><span class="token punctuation">(</span><span class="token string">"ASP.NET"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

Debug<span class="token punctuation">.</span><span class="token function">Print</span><span class="token punctuation">(</span>$<span class="token string">"Found {items.Count()} items."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">foreach</span> <span class="token punctuation">(</span>FindResult item <span class="token keyword">in</span> items<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    Debug<span class="token punctuation">.</span><span class="token function">Print</span><span class="token punctuation">(</span>$<span class="token string">"Found at {item.RelativeStartIndex} "</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    Debug<span class="token punctuation">.</span><span class="token function">Print</span><span class="token punctuation">(</span>$<span class="token string">"Found: {item.FullMatchText}"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Searching a spreadsheet works similarly. The differences:</p><ul><li>The <code>FindAll</code> method is built right into the <code>Workbook</code> object.</li><li>You have more search options available with the spreadsheet object.</li><li>You pass your search string as part of the options object.</li></ul><p>My find code with a workbook would look like this:</p><pre class=" language-csharp"><code class="prism  language-csharp">FindOptions opts <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>
FindWhat <span class="token operator">=</span> <span class="token string">"ASP.NET"</span><span class="token punctuation">,</span>
MatchCase <span class="token operator">=</span> <span class="token keyword">false</span><span class="token punctuation">,</span>
MatchEntireCellContents <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>

IEnumerable<span class="token operator">&lt;</span>FindResult<span class="token operator">&gt;</span> items <span class="token operator">=</span> doc<span class="token punctuation">.</span><span class="token function">FindAll</span><span class="token punctuation">(</span>opts<span class="token punctuation">)</span><span class="token punctuation">;</span>

Debug<span class="token punctuation">.</span><span class="token function">Print</span><span class="token punctuation">(</span>$<span class="token string">"Found {items.Count()} items."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">foreach</span><span class="token punctuation">(</span>FindResult item <span class="token keyword">in</span> items<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    Debug<span class="token punctuation">.</span><span class="token function">Print</span><span class="token punctuation">(</span>$<span class="token string">"Found at {item.FoundCell.CellIndex} "</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    Debug<span class="token punctuation">.</span><span class="token function">Print</span><span class="token punctuation">(</span>$<span class="token string">"Found: {item.ResultValue}"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>One note: It is certainly convenient when objects from the different libraries share the same name (like the <code>FindResult</code> object that&rsquo;s defined in both the <code>RadFlowDocument</code> and <code>Workbook</code> libraries). However, if you try to use both <code>FindResult</code> objects in the same code file, the compiler will get confused because the two objects are in different namespaces. In the unlikely case that you&rsquo;re working with both Excel and Word documents in the same code file, you&rsquo;ll have to fully qualify the object names&mdash;something I haven&rsquo;t done in this post.</p><h2 id="saving-your-documents">Saving Your Documents</h2><p>To save your modified documents back to disk, you just need to use the provider&rsquo;s <code>Export</code> method. The code for all the document types is identical:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">using</span> <span class="token punctuation">(</span>Stream str <span class="token operator">=</span> File<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span><span class="token string">@"wwwroot/documents/Prioritiesnew.&lt;filetype&gt;"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    prov<span class="token punctuation">.</span><span class="token function">Export</span><span class="token punctuation">(</span>doc<span class="token punctuation">,</span>str<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">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><h2 id="converting-documents">Converting Documents</h2><p>You can convert from one type in the suite to other types and, not surprisingly, the conversion processes look very much alike. As you&rsquo;ve seen before, it often comes down to using the right provider.</p><p>If, for example, you want plain text version of your PDF file, you use the <code>TextFormatProvider</code> object&rsquo;s <code>Export</code> method:</p><pre class=" language-csharp"><code class="prism  language-csharp">TextFormatProvider prov <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">string</span> text <span class="token operator">=</span> prov<span class="token punctuation">.</span><span class="token function">Export</span><span class="token punctuation">(</span>doc<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">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>For Word/HTML/RTF document types, the code is almost identical except it uses the <code>TxtFormatProvider</code> object:</p><pre class=" language-csharp"><code class="prism  language-csharp">TxtFormatProvider txProv <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">string</span> text <span class="token operator">=</span> prov<span class="token punctuation">.</span><span class="token function">Export</span><span class="token punctuation">(</span>doc<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">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            
</code></pre><p>One note: There is a downside to having the classes that do similar things to different document types have the same name. If you are mixing document types and, as a result, using the Fixed, Flow and spreadsheet libraries in the same application, the compiler can get confused about which class from which library you&rsquo;re using. If so, you&rsquo;ll have to <a target="_blank" href="https://docs.telerik.com/devtools/document-processing/knowledge-base/cs0104-error-pdf-format-provider">fully qualify your class names</a> by including their namespaces in the class names. That makes for hard-to-read code, so I haven&rsquo;t done that here.</p><p>But, as an example of how different documents require different functionality, you probably wouldn&rsquo;t ever want to convert an Excel workbook to a string &hellip; but you might want to save your workbook as a CSV file. As you might expect by now, the code to save your imported workbook into a CSV file just means using the <code>Export</code> method on the appropriate provider&mdash;the <code>CsvFormatProvider</code> object in this case.</p><p>Typical code would look like this:</p><pre class=" language-csharp"><code class="prism  language-csharp">CsvFormatProvider prov <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">using</span> <span class="token punctuation">(</span>Stream str <span class="token operator">=</span> File<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span><span class="token string">"Priority.csv"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    prov<span class="token punctuation">.</span><span class="token function">Export</span><span class="token punctuation">(</span>doc<span class="token punctuation">,</span> str<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">10</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 target="_blank" href="https://www.telerik.com/blogs/quick-and-easy-conversion-to-pdf-with-telerik-document-processing-library">Converting any of these document types (Excel, Word, HTML, etc.) to PDF</a> is equally straightforward. Because all the libraries look very much alike, it&rsquo;s really just a matter of adding the library with the provider you need.</p><p>But you can also convert your <code>Workbook</code> object into a <code>RadFixedDocument</code> if you wanted to manipulate your spreadsheet as a PDF object. That conversion is handled by the PdfFormatProvider from the Telerik.Windows.Documents.Spreadsheet.Formatproviders.Pdf package and using its <code>ExportToFixedDocument</code>method:</p><pre class=" language-csharp"><code class="prism  language-csharp">PdfFormatProvider prov <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>

RadFixedDocument fixedDoc <span class="token operator">=</span> 
        prov<span class="token punctuation">.</span><span class="token function">ExportToFixedDocument</span><span class="token punctuation">(</span>doc<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">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The code is identical if you want to convert a Word/RTF/HTML document to a <code>RadFixedDocument</code> to work with it as a PDF file. That conversion also uses a <code>PdfFormatProvider</code> object but, this time, from the Telerik.Windows.Documents.Flow.FormatProviders.Pdf namespace.</p><p>But, because the providers from the two libraries have the same name, if you&rsquo;re using both libraries in the same code file, you will need to fully qualify your provider names to make sure you&rsquo;re getting the appropriate <code>PdfFormatProvider</code>.</p><p>Of course, once you start using these tools to create or modify the documents you&rsquo;ve loaded, you&rsquo;ll find more differences&mdash;the functionality in a spreadsheet is very different from the functionality in an HTML document. But, while the family resemblances among this suite won&rsquo;t eliminate those differences, it does cut those differences down to what matters: how those documents differ in their functionality. Which is, after all, what you want.</p><hr /><p>Explore Telerik Document Processing Libraries, plus component libraries, reporting and more with a free trial of the Telerik DevCraft bundle:</p><p><a href="https://www.telerik.com/download" class="Btn" target="_blank">Try DevCraft</a></p><img src="https://feeds.telerik.com/link/10827/17310586.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-04-18T12:15:37Z</updated>
    <author>
      <name>Héctor Pérez </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17309762/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/10827/17309762.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:14170089-af04-485a-941c-24cdfcf23d33</id>
    <title type="text">Kendo UI for jQuery: AI Coding Assistant</title>
    <summary type="text">See how the Kendo UI for jQuery AI Coding Assistant can help speed up development and prototyping with an MCP server that provides contextually aware code that follows Kendo UI patterns.</summary>
    <published>2026-03-30T14:22:14Z</published>
    <updated>2026-04-18T12:15:37Z</updated>
    <author>
      <name>Hassan Djirdeh </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17309595/kendo-ui-jquery-ai-coding-assistant"/>
    <content type="text"><![CDATA[<p><span class="featured">See how the Kendo UI for jQuery AI Coding Assistant can help speed up development and prototyping with an MCP server that provides contextually aware code that follows Kendo UI patterns.</span></p><p>AI-powered coding assistants have become an important part of modern software engineering workflows. While AI tools excel at generating code quickly, they still require solid context to deliver their full value. This context becomes even more important when working with a UI library like Progress <a target="_blank" href="https://www.telerik.com/kendo-jquery-ui">Kendo UI for jQuery</a>, where correct APIs and configuration patterns matter. This is where the <a target="_blank" href="https://www.telerik.com/kendo-jquery-ui/documentation/ai-assistant/overview">Kendo UI for jQuery AI Coding Assistant</a> comes in.</p><p>In this article, we&rsquo;ll explore what the AI Coding Assistant offers and how it helps speed up component development and prototyping when building applications with Kendo UI for jQuery.</p><blockquote><p><strong>Prerequisites:</strong> To use the Kendo UI for jQuery AI Coding Assistant, you&rsquo;ll need a compatible MCP client (we&rsquo;ll be using <a target="_blank" href="https://cursor.com/">Cursor</a> in this article), an active Kendo UI for jQuery license (or trial) and an application that includes Kendo UI for jQuery.</p></blockquote><h2 id="mcp-model-context-protocol">MCP (Model Context Protocol)</h2><p><a target="_blank" href="https://docs.anthropic.com/en/docs/mcp">Model Context Protocol (MCP)</a> is an open standard developed by <a target="_blank" href="https://www.anthropic.com/">Anthropic</a> that standardizes how applications provide context to AI models and agents. Think of it as a common language that allows different systems to share information with AI in a structured way.</p><p>MCP works through servers that expose specific tools and knowledge to AI clients. When we install an MCP server, we&rsquo;re essentially giving our AI assistant access to specialized expertise in a particular domain. For Kendo UI for jQuery, this means the AI can understand component APIs, configuration options and implementation patterns that it wouldn&rsquo;t otherwise know about.</p><p>The Kendo UI for jQuery AI Coding Assistant is integrated into an MCP Server, which means any MCP-compatible client (like Cursor or VS Code) can tap into this specialized knowledge.</p><blockquote><p>Check out the article <a target="_blank" href="https://www.telerik.com/blogs/promise-model-context-protocol">The Promise of Model Context Protocol</a> for more details on MCP and what it offers.</p></blockquote><h2 id="setting-up-the-mcp-server-with-cursor">Setting Up the MCP Server with Cursor</h2><p><a target="_blank" href="https://cursor.com/">Cursor</a> is an AI-powered code editor that has native support for MCP servers. Let&rsquo;s walk through the setup process.</p><h3 id="configuring-the-mcp-server">Configuring the MCP Server</h3><p>The first step is creating the MCP configuration file. In the root of our Kendo UI for jQuery project, we&rsquo;ll create a <code>.cursor</code> folder with an <code>mcp.json</code> file:</p><pre class=" language-json"><code class="prism  language-json"><span class="token punctuation">{</span>
  <span class="token string">"mcpServers"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"kendo-jquery-assistant"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"stdio"</span><span class="token punctuation">,</span>
      <span class="token string">"command"</span><span class="token punctuation">:</span> <span class="token string">"npx"</span><span class="token punctuation">,</span>
      <span class="token string">"args"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"-y"</span><span class="token punctuation">,</span> <span class="token string">"@progress/kendo-jquery-mcp@latest"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token string">"env"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
        <span class="token string">"TELERIK_LICENSE_PATH"</span><span class="token punctuation">:</span> <span class="token string">"./telerik-license.txt"</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 configuration tells Cursor to set up the Kendo UI for jQuery MCP server with the name <code>kendo-jquery-assistant</code>. The <code>TELERIK_LICENSE_PATH</code> environment variable should point to the location of our Telerik license file.</p><blockquote><p>After creating the <code>mcp.json</code> file, you may need to restart Cursor to pick up the new MCP configuration.</p></blockquote><h3 id="enabling-mcp-in-cursor-settings">Enabling MCP in Cursor Settings</h3><p>Once we&rsquo;ve set up the configuration file, we&rsquo;ll need to verify the MCP server is enabled in Cursor&rsquo;s settings. We can open Cursor settings and navigate to the &ldquo;MCP Tools&rdquo; section, and we should see our <code>kendo-jquery-assistant</code> server listed there. We can toggle it on to enable the server.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/kendo-jquery-mcp-cursor-enabled.png?sfvrsn=1c47b734_2" alt="Cursor settings - MCP Tools - kendo-jquery-assistant server toggled on." /></p><p>When the server appears in the list and is enabled, we&rsquo;re ready to start using the AI Coding Assistant.</p><h2 id="using-the-ai-coding-assistant">Using the AI Coding Assistant</h2><p>Before we dive into examples, there are a couple of things to keep in mind when working with the Kendo UI for jQuery AI Coding Assistant.</p><p>First, we need to make sure our prompts start with one of these trigger phrases: <code>/kendojquery</code> or <code>@kendojquery</code>, which tells Cursor to use the MCP server.</p><p>Second, we should verify that the MCP server is actually being used. We&rsquo;ll look for confirmation messages like &ldquo;Running kendo-jquery-assistant&rdquo; or similar statements in the output. If we don&rsquo;t see this, we might need to rephrase our prompt or check our configuration.</p><h2 id="building-a-grid-with-the-help-of-the-ai-coding-assistant">Building a Grid with the Help of the AI Coding Assistant</h2><p>Now that we have the Kendo UI for jQuery AI Coding Assistant configured, let&rsquo;s explore how it enhances our development workflow by building a <a target="_blank" href="https://demos.telerik.com/kendo-ui/grid/index">Kendo UI Grid</a>.</p><p>Before we start prompting, here&rsquo;s the base HTML file we&rsquo;ll be working with. It includes the Kendo UI theme, jQuery and the Kendo UI for jQuery scripts:</p><pre class=" language-html"><code class="prism  language-html"><span class="token doctype">&lt;!DOCTYPE html&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</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>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>utf-8<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>title</span><span class="token punctuation">&gt;</span></span>Kendo UI jQuery Grid Example<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">&gt;</span></span>

    <span class="token comment">&lt;!-- Kendo UI default theme --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>stylesheet<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>https://kendo.cdn.telerik.com/themes/12.3.0/default/default-main.css<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>

    <span class="token comment">&lt;!-- jQuery first --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>https://code.jquery.com/jquery-3.7.0.min.js<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><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 comment">&lt;!-- Kendo UI for jQuery --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>https://kendo.cdn.telerik.com/2025.4.1321/js/kendo.all.min.js<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><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 comment">&lt;!-- License script --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>telerik-license.js<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><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>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>h1</span><span class="token punctuation">&gt;</span></span>My Kendo UI Grid<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>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>With this foundation in place, we can start using the AI Coding Assistant to build our Grid.</p><h3 id="creating-a-basic-grid-with-sorting-and-paging">Creating a Basic Grid with Sorting and Paging</h3><p>We&rsquo;ll start with a simple prompt to create a Grid from scratch:</p><p><strong>Prompt:</strong> <code>@kendojquery Generate a Kendo UI for jQuery Grid with sorting and paging enabled. Bind the Grid to dummy data.</code></p><p>The MCP server processes this request and provides us with a complete implementation.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/kendo-jquery-mcp-example-1.gif?sfvrsn=69ee97d2_2" alt="MCP server processing request: kendojquery generate a Kendo UI for jQuery Grid with sorting and paging enabled. Bind the Grid to dummy data. And a grid shows up in our app!" /></p><p>The generated code includes everything we need to get started:</p><pre class=" language-html"><code class="prism  language-html"><span class="token doctype">&lt;!DOCTYPE html&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</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>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>utf-8<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>title</span><span class="token punctuation">&gt;</span></span>Kendo UI jQuery Grid Example<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">&gt;</span></span>

    <span class="token comment">&lt;!-- Kendo UI default theme --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>stylesheet<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>https://kendo.cdn.telerik.com/themes/12.3.0/default/default-main.css<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>

    <span class="token comment">&lt;!-- jQuery first --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>https://code.jquery.com/jquery-3.7.0.min.js<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><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 comment">&lt;!-- Kendo UI for jQuery --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>https://kendo.cdn.telerik.com/2025.4.1321/js/kendo.all.min.js<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><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 comment">&lt;!-- License script --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>telerik-license.js<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><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>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>h1</span><span class="token punctuation">&gt;</span></span>My Kendo UI Grid<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">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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 punctuation">&gt;</span></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 script language-javascript">
      <span class="token function">$</span><span class="token punctuation">(</span>document<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ready</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// Dummy data for the Grid</span>
        <span class="token keyword">const</span> orderData <span class="token operator">=</span> <span class="token punctuation">[</span>
          <span class="token punctuation">{</span> OrderID<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> OrderDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">"2024-11-06"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> Freight<span class="token punctuation">:</span> <span class="token number">12.34</span><span class="token punctuation">,</span> ShipCity<span class="token punctuation">:</span> <span class="token string">"Antwerp"</span><span class="token punctuation">,</span> ShipCountry<span class="token punctuation">:</span> <span class="token string">"Belgium"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">{</span> OrderID<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> OrderDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">"2024-03-02"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> Freight<span class="token punctuation">:</span> <span class="token number">23.45</span><span class="token punctuation">,</span> ShipCity<span class="token punctuation">:</span> <span class="token string">"Singapore"</span><span class="token punctuation">,</span> ShipCountry<span class="token punctuation">:</span> <span class="token string">"Singapore"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">{</span> OrderID<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span> OrderDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">"2024-06-26"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> Freight<span class="token punctuation">:</span> <span class="token number">34.56</span><span class="token punctuation">,</span> ShipCity<span class="token punctuation">:</span> <span class="token string">"Shanghai"</span><span class="token punctuation">,</span> ShipCountry<span class="token punctuation">:</span> <span class="token string">"China"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">{</span> OrderID<span class="token punctuation">:</span> <span class="token number">4</span><span class="token punctuation">,</span> OrderDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">"2024-09-20"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> Freight<span class="token punctuation">:</span> <span class="token number">45.67</span><span class="token punctuation">,</span> ShipCity<span class="token punctuation">:</span> <span class="token string">"Hamburg"</span><span class="token punctuation">,</span> ShipCountry<span class="token punctuation">:</span> <span class="token string">"Germany"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">{</span> OrderID<span class="token punctuation">:</span> <span class="token number">5</span><span class="token punctuation">,</span> OrderDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">"2024-12-12"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> Freight<span class="token punctuation">:</span> <span class="token number">56.78</span><span class="token punctuation">,</span> ShipCity<span class="token punctuation">:</span> <span class="token string">"Mumbai"</span><span class="token punctuation">,</span> ShipCountry<span class="token punctuation">:</span> <span class="token string">"India"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">{</span> OrderID<span class="token punctuation">:</span> <span class="token number">6</span><span class="token punctuation">,</span> OrderDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">"2025-02-08"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> Freight<span class="token punctuation">:</span> <span class="token number">67.89</span><span class="token punctuation">,</span> ShipCity<span class="token punctuation">:</span> <span class="token string">"Shanghai"</span><span class="token punctuation">,</span> ShipCountry<span class="token punctuation">:</span> <span class="token string">"China"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">{</span> OrderID<span class="token punctuation">:</span> <span class="token number">7</span><span class="token punctuation">,</span> OrderDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">"2025-05-05"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> Freight<span class="token punctuation">:</span> <span class="token number">78.90</span><span class="token punctuation">,</span> ShipCity<span class="token punctuation">:</span> <span class="token string">"Tokyo"</span><span class="token punctuation">,</span> ShipCountry<span class="token punctuation">:</span> <span class="token string">"Japan"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">{</span> OrderID<span class="token punctuation">:</span> <span class="token number">8</span><span class="token punctuation">,</span> OrderDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">"2025-08-03"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> Freight<span class="token punctuation">:</span> <span class="token number">89.01</span><span class="token punctuation">,</span> ShipCity<span class="token punctuation">:</span> <span class="token string">"Port Klang"</span><span class="token punctuation">,</span> ShipCountry<span class="token punctuation">:</span> <span class="token string">"Malaysia"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">{</span> OrderID<span class="token punctuation">:</span> <span class="token number">9</span><span class="token punctuation">,</span> OrderDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">"2025-10-29"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> Freight<span class="token punctuation">:</span> <span class="token number">90.12</span><span class="token punctuation">,</span> ShipCity<span class="token punctuation">:</span> <span class="token string">"Rotterdam"</span><span class="token punctuation">,</span> ShipCountry<span class="token punctuation">:</span> <span class="token string">"Netherlands"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">{</span> OrderID<span class="token punctuation">:</span> <span class="token number">10</span><span class="token punctuation">,</span> OrderDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">"2025-01-23"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> Freight<span class="token punctuation">:</span> <span class="token number">10.32</span><span class="token punctuation">,</span> ShipCity<span class="token punctuation">:</span> <span class="token string">"Vancouver"</span><span class="token punctuation">,</span> ShipCountry<span class="token punctuation">:</span> <span class="token string">"Canada"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">{</span> OrderID<span class="token punctuation">:</span> <span class="token number">11</span><span class="token punctuation">,</span> OrderDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">"2024-04-17"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> Freight<span class="token punctuation">:</span> <span class="token number">21.43</span><span class="token punctuation">,</span> ShipCity<span class="token punctuation">:</span> <span class="token string">"Col&oacute;n"</span><span class="token punctuation">,</span> ShipCountry<span class="token punctuation">:</span> <span class="token string">"Panama"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">{</span> OrderID<span class="token punctuation">:</span> <span class="token number">12</span><span class="token punctuation">,</span> OrderDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">"2024-07-11"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> Freight<span class="token punctuation">:</span> <span class="token number">32.54</span><span class="token punctuation">,</span> ShipCity<span class="token punctuation">:</span> <span class="token string">"Manila"</span><span class="token punctuation">,</span> ShipCountry<span class="token punctuation">:</span> <span class="token string">"Philippines"</span> <span class="token punctuation">}</span>
        <span class="token punctuation">]</span><span class="token punctuation">;</span>

        <span class="token comment">// Initialize the Grid</span>
        <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">"#grid"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">kendoGrid</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
          dataSource<span class="token punctuation">:</span> <span class="token punctuation">{</span>
            data<span class="token punctuation">:</span> orderData<span class="token punctuation">,</span>
            schema<span class="token punctuation">:</span> <span class="token punctuation">{</span>
              model<span class="token punctuation">:</span> <span class="token punctuation">{</span>
                fields<span class="token punctuation">:</span> <span class="token punctuation">{</span>
                  OrderID<span class="token punctuation">:</span> <span class="token punctuation">{</span> type<span class="token punctuation">:</span> <span class="token string">"number"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
                  OrderDate<span class="token punctuation">:</span> <span class="token punctuation">{</span> type<span class="token punctuation">:</span> <span class="token string">"date"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
                  Freight<span class="token punctuation">:</span> <span class="token punctuation">{</span> type<span class="token punctuation">:</span> <span class="token string">"number"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
                  ShipCity<span class="token punctuation">:</span> <span class="token punctuation">{</span> type<span class="token punctuation">:</span> <span class="token string">"string"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
                  ShipCountry<span class="token punctuation">:</span> <span class="token punctuation">{</span> type<span class="token punctuation">:</span> <span class="token string">"string"</span> <span class="token punctuation">}</span>
                <span class="token punctuation">}</span>
              <span class="token punctuation">}</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
            pageSize<span class="token punctuation">:</span> <span class="token number">5</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
          columns<span class="token punctuation">:</span> <span class="token punctuation">[</span>
            <span class="token punctuation">{</span> field<span class="token punctuation">:</span> <span class="token string">"OrderID"</span><span class="token punctuation">,</span> title<span class="token punctuation">:</span> <span class="token string">"Order ID"</span><span class="token punctuation">,</span> width<span class="token punctuation">:</span> <span class="token number">100</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">{</span> field<span class="token punctuation">:</span> <span class="token string">"OrderDate"</span><span class="token punctuation">,</span> title<span class="token punctuation">:</span> <span class="token string">"Order Date"</span><span class="token punctuation">,</span> format<span class="token punctuation">:</span> <span class="token string">"{0:yyyy-MM-dd}"</span><span class="token punctuation">,</span> width<span class="token punctuation">:</span> <span class="token number">150</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">{</span> field<span class="token punctuation">:</span> <span class="token string">"Freight"</span><span class="token punctuation">,</span> title<span class="token punctuation">:</span> <span class="token string">"Freight"</span><span class="token punctuation">,</span> format<span class="token punctuation">:</span> <span class="token string">"{0:c2}"</span><span class="token punctuation">,</span> width<span class="token punctuation">:</span> <span class="token number">120</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">{</span> field<span class="token punctuation">:</span> <span class="token string">"ShipCity"</span><span class="token punctuation">,</span> title<span class="token punctuation">:</span> <span class="token string">"Ship City"</span><span class="token punctuation">,</span> width<span class="token punctuation">:</span> <span class="token number">150</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">{</span> field<span class="token punctuation">:</span> <span class="token string">"ShipCountry"</span><span class="token punctuation">,</span> title<span class="token punctuation">:</span> <span class="token string">"Ship Country"</span> <span class="token punctuation">}</span>
          <span class="token punctuation">]</span><span class="token punctuation">,</span>
          sortable<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
          pageable<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
          height<span class="token punctuation">:</span> <span class="token number">400</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><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>The code includes realistic dummy data, proper <code>Grid</code> initialization with jQuery&rsquo;s document ready pattern and appropriate configuration for sorting and paging.</p><p>This is where the AI Coding Assistant really shines. Instead of receiving generic code that may not work correctly with Kendo UI for jQuery, we&rsquo;re getting code that follows the library&rsquo;s practices and patterns.</p><h3 id="adding-filtering-capabilities">Adding Filtering Capabilities</h3><p>Building on our basic Grid, let&rsquo;s add filtering functionality with a follow-up prompt:</p><p><strong>Prompt:</strong> <code>@kendojquery Can we add filtering to this Grid?</code></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/kendo-jquery-mcp-example-2.gif?sfvrsn=fa79d56a_2" alt="With prompt: @kendojquery Can we add filtering to this Grid? we have a filter option available in our app grid" /></p><p>The MCP server understands our existing context and enhances the implementation:</p><pre class=" language-js"><code class="prism  language-js"><span class="token function">$</span><span class="token punctuation">(</span><span class="token string">"#grid"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">kendoGrid</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  dataSource<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    data<span class="token punctuation">:</span> orderData<span class="token punctuation">,</span>
    schema<span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token comment">// ...</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    pageSize<span class="token punctuation">:</span> <span class="token number">5</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  columns<span class="token punctuation">:</span> <span class="token punctuation">[</span>
    <span class="token comment">// ...</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
  sortable<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
  filterable<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// filterable is added</span>
  pageable<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
  height<span class="token punctuation">:</span> <span class="token number">400</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The MCP server intelligently added the <code>filterable: true</code> property to our Grid configuration, which demonstrates how we can iteratively build up our components through conversation with the AI.</p><h3 id="enabling-inline-editing">Enabling Inline Editing</h3><p>We&rsquo;ll take our Grid one step further by adding the ability to edit cells inline:</p><p><strong>Prompt:</strong> <code>@kendojquery Can we make the ship city and ship country columns editable inline?</code></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/kendo-jquery-mcp-example-3.gif?sfvrsn=4cbe301c_1" alt="With prompt: @kendojquery Can we make the ship city and ship country columns editable inline?, we add editing capabilities to our jQuery Grid." /></p><p>The MCP server enhances our Grid with editing capabilities:</p><pre class=" language-js"><code class="prism  language-js"><span class="token function">$</span><span class="token punctuation">(</span><span class="token string">"#grid"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">kendoGrid</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  dataSource<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    data<span class="token punctuation">:</span> orderData<span class="token punctuation">,</span>
    schema<span class="token punctuation">:</span> <span class="token punctuation">{</span>
      OrderID<span class="token punctuation">:</span> <span class="token punctuation">{</span> type<span class="token punctuation">:</span> <span class="token string">"number"</span><span class="token punctuation">,</span> editable<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      OrderDate<span class="token punctuation">:</span> <span class="token punctuation">{</span> type<span class="token punctuation">:</span> <span class="token string">"date"</span><span class="token punctuation">,</span> editable<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      Freight<span class="token punctuation">:</span> <span class="token punctuation">{</span> type<span class="token punctuation">:</span> <span class="token string">"number"</span><span class="token punctuation">,</span> editable<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token comment">// adding editable: true to these columns</span>
      ShipCity<span class="token punctuation">:</span> <span class="token punctuation">{</span> type<span class="token punctuation">:</span> <span class="token string">"string"</span><span class="token punctuation">,</span> editable<span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      ShipCountry<span class="token punctuation">:</span> <span class="token punctuation">{</span> type<span class="token punctuation">:</span> <span class="token string">"string"</span><span class="token punctuation">,</span> editable<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>
    pageSize<span class="token punctuation">:</span> <span class="token number">5</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  columns<span class="token punctuation">:</span> <span class="token punctuation">[</span>
    <span class="token comment">// ...</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token comment">// ...</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The MCP server understood exactly what we needed. It added the <code>editable</code> property and configured the dataSource schema to specify which fields should be editable. The <code>OrderID</code>, <code>OrderDate</code> and <code>Freight</code> fields are marked as non-editable, while <code>ShipCity</code> and <code>ShipCountry</code> can be edited directly in the Grid cells.</p><p>This iterative approach shows the power of working with the AI Coding Assistant. We started with a basic Grid and progressively added sorting, paging, filtering, and now inline editing, all through natural conversation.</p><h2 id="wrap-up">Wrap-up</h2><p>While much of the AI coding hype focuses on newer frameworks, the Kendo UI for jQuery AI Coding Assistant shows that teams working with established technologies like jQuery can still benefit from these same productivity gains.</p><p>In this article, we&rsquo;ve seen how the MCP server provides contextually aware code that follows Kendo UI patterns. Instead of fixing generic AI output or cross-referencing documentation, we can iterate quickly and let the assistant handle the component-specific details.</p><p>For more details, check out the official <a target="_blank" href="https://www.telerik.com/kendo-jquery-ui/documentation/ai-assistant/overview">Kendo UI for jQuery AI Coding Assistant documentation</a>. And don&rsquo;t forget, you can try it yourself, free for 30 days!</p><p><a target="_blank" href="https://www.telerik.com/try/kendo-ui" class="Btn">Try Kendo UI for jQuery</a></p><img src="https://feeds.telerik.com/link/10827/17309595.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:95899eab-1403-49cb-a14e-eb2d73abeed4</id>
    <title type="text">Learning Vercel AI SDK—Part 2: Creating Your First Agent</title>
    <summary type="text">With the Vercel AI SDK project we set up last time, today we will learn how to build our first agent!</summary>
    <published>2026-03-27T17:15:00Z</published>
    <updated>2026-04-18T12:15:37Z</updated>
    <author>
      <name>Dhananjay Kumar </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17307665/learning-vercel-ai-sdk-part-2-creating-your-first-agent"/>
    <content type="text"><![CDATA[<p><span class="featured">With the Vercel AI SDK project we set up last time, today we will learn how to build our first agent!</span></p><p>If you have not yet read <a href="https://www.telerik.com/blogs/learning-vercel-ai-sdk-part-1">Learning Vercel AI SDK&mdash;Part 1</a>, that is the best way to get started to follow along today.</p><p>In this article, we will learn how to build your first AI agent using the Vercel AI SDK and OpenAI. We are going to use:</p><ul><li>TypeScript</li><li>Vercel AI SDK</li><li>OpenAI</li></ul><p>Before getting started, make sure you have the required setup and OpenAI API key. You can <a href="https://platform.openai.com/settings/organization/api-keys" target="_blank">get an API key from here</a>.</p><h2 id="setting-up-the-project">Setting Up the Project</h2><p>To get started, create a new Node.js application and set it up to use TypeScript. For that, in your terminal, run the following commands:</p><pre><code>npm install -D typescript @types/node ts-node
npx tsc  -init
</code></pre><p>Once the commands have been executed, replace the contents of your tsconfig.json file with the configuration shown below.</p><pre class=" language-json"><code class="prism  language-json"><span class="token punctuation">{</span>
  <span class="token string">"compilerOptions"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"target"</span><span class="token punctuation">:</span> <span class="token string">"ES2022"</span><span class="token punctuation">,</span> 
    <span class="token string">"module"</span><span class="token punctuation">:</span> <span class="token string">"ES2022"</span><span class="token punctuation">,</span>
    <span class="token string">"moduleResolution"</span><span class="token punctuation">:</span> <span class="token string">"node"</span><span class="token punctuation">,</span>
    <span class="token string">"rootDir"</span><span class="token punctuation">:</span> <span class="token string">"./src"</span><span class="token punctuation">,</span>
    <span class="token string">"outDir"</span><span class="token punctuation">:</span> <span class="token string">"./dist"</span><span class="token punctuation">,</span>
    <span class="token string">"strict"</span><span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token string">"esModuleInterop"</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 string">"include"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"src/**/*"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token string">"exclude"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"node_modules"</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span>
</code></pre><p>After that, install the dependencies below:</p><ul><li>npm install dotenv</li><li>npm install -D @types/dotenv</li><li>npm install -D @types/node tsx typescript</li><li>npm i --save-dev @types/json-schema</li><li>npm install ai @ai-sdk/openai zod</li></ul><p>Next, add the .env file to the project root and paste the OpenAI key information below inside the file.</p><pre><code>OPENAI_API_KEY= ""
</code></pre><p>Now that you&rsquo;ve added your API key and installed all the dependencies, you&rsquo;ll notice that your package.json file has been updated with these changes.</p><pre class=" language-json"><code class="prism  language-json"><span class="token punctuation">{</span>
  <span class="token string">"name"</span><span class="token punctuation">:</span><span class="token string">"agent1"</span><span class="token punctuation">,</span>
  <span class="token string">"main"</span><span class="token punctuation">:</span> <span class="token string">"index.js"</span><span class="token punctuation">,</span>
  <span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"module"</span><span class="token punctuation">,</span>
  <span class="token string">"scripts"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"build"</span><span class="token punctuation">:</span> <span class="token string">"tsc"</span><span class="token punctuation">,</span>
    <span class="token string">"start"</span><span class="token punctuation">:</span> <span class="token string">"tsc &amp;&amp; node dist/index.js"</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  <span class="token string">"devDependencies"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"@types/dotenv"</span><span class="token punctuation">:</span> <span class="token string">"^6.1.1"</span><span class="token punctuation">,</span>
    <span class="token string">"@types/json-schema"</span><span class="token punctuation">:</span> <span class="token string">"^7.0.15"</span><span class="token punctuation">,</span>
    <span class="token string">"@types/node"</span><span class="token punctuation">:</span> <span class="token string">"^25.0.6"</span><span class="token punctuation">,</span>
    <span class="token string">"ts-node"</span><span class="token punctuation">:</span> <span class="token string">"^10.9.2"</span><span class="token punctuation">,</span>
    <span class="token string">"tsx"</span><span class="token punctuation">:</span> <span class="token string">"^4.21.0"</span><span class="token punctuation">,</span>
    <span class="token string">"typescript"</span><span class="token punctuation">:</span> <span class="token string">"^5.9.3"</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token string">"dependencies"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"@ai-sdk/openai"</span><span class="token punctuation">:</span> <span class="token string">"^3.0.7"</span><span class="token punctuation">,</span>
    <span class="token string">"ai"</span><span class="token punctuation">:</span> <span class="token string">"^6.0.27"</span><span class="token punctuation">,</span>
    <span class="token string">"dotenv"</span><span class="token punctuation">:</span> <span class="token string">"^17.2.3"</span><span class="token punctuation">,</span>
    <span class="token string">"zod"</span><span class="token punctuation">:</span> <span class="token string">"^4.3.5"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>In your setup, the package name and version may differ. Next, create a src folder in your project and add an index.ts file inside it. In that file, log the value of your OpenAI key to verify that the project has been configured correctly.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> dotenv <span class="token keyword">from</span> <span class="token string">'dotenv'</span><span class="token punctuation">;</span>
dotenv<span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> openaiApiKey<span class="token punctuation">:</span> <span class="token keyword">string</span> <span class="token operator">|</span> undefined <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span>OPENAI_API_KEY<span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`OpenAI API Key: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>openaiApiKey<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>When you execute <code>npm run start</code> in your terminal, you should see your OpenAI key printed in the console.</p><p>Agents use tools to perform tasks. So let&rsquo;s start with creating tools.</p><h2 id="creating-a-tool">Creating a Tool</h2><p>We&rsquo;ll begin by creating a very simple tool. The Vercel AI SDK makes it very straightforward to create a tool. You call the tool function and pass an object in it. The input object has properties such as, description, inputSchema and asynchronous execute function.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> tool<span class="token punctuation">,</span> zodSchema <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"ai"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> z <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> getTimeTool <span class="token operator">=</span> <span class="token function">tool</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    description<span class="token punctuation">:</span> <span class="token string">'Returns the current date and time in ISO format.'</span><span class="token punctuation">,</span>
    inputSchema<span class="token punctuation">:</span> <span class="token function">zodSchema</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">object</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>
    execute<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span> time<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toISOString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The above tool returns the time in ISO format. Notice:</p><ul><li>Schema: <code>z.object({})</code> : That means model is instructed that to call this tool by passing an empty object.</li><li><code>inputSchema: zodSchema(z.object({}))</code>: That means the tool&rsquo;s input is an empty object; the model should not pass any arguments, and the SDK will enforce that.</li></ul><p>So, the <code>getTimeTool</code> returns an object containing current time in ISO format.</p><p>Next, let&rsquo;s create one more tool to greet the person.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> tool<span class="token punctuation">,</span> zodSchema <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'ai'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'zod'</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> greetTool <span class="token operator">=</span> <span class="token function">tool</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    description<span class="token punctuation">:</span> <span class="token string">'Greets a person by name. Use when the user says hello or asks to greet someone.'</span><span class="token punctuation">,</span>
    inputSchema<span class="token punctuation">:</span> <span class="token function">zodSchema</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      name<span class="token punctuation">:</span> z<span class="token punctuation">.</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 function">describe</span><span class="token punctuation">(</span><span class="token string">'Name of the person to greet'</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>
    execute<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> name <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`Hello, </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">!`</span></span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>This tool takes person name as input parameter and a prints greeting message.</p><h2 id="creating-agent">Creating Agent</h2><p>We will now use these two tools within an agent to generate a greeting that includes the current time in ISO 8601 format.</p><p>To orchestrate tool execution, instantiate an agent using the <code>ToolLoopAgent</code> class. This agent is responsible for iterative tool invocation and model coordination. As shown below, the constructor requires three primary inputs:</p><ul><li><code>model</code> &mdash; The underlying LLM responsible for reasoning and tool selection</li><li><code>instructions</code> &mdash; A system-level directive that constrains behavior (e.g., instructing the agent to greet the user and include the current time in ISO format)</li><li><code>tools</code> &mdash; An array of tool definitions that the agent is authorized to invoke during execution</li></ul><p>By injecting the previously defined tools into the tools array, the agent can call them as needed, retrieve the current timestamp, format it in ISO 8601 and construct the greeting deterministically.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">var</span> system <span class="token operator">=</span> <span class="token template-string"><span class="token string">`You are a helpful assistant. For this task you MUST:
1. First call the gettime tool to get the current time in ISO format.
2. Then call the greet tool with the person's name (e.g. DJ).
3. After you have called BOTH tools and received their results, write one short final message that greets the person and includes the time in ISO format (e.g. "Hey DJ, here is the time in ISO format: ...").
Do not skip the tools. Call both gettime and greet first, then write your final combined message.`</span></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> myAgent <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ToolLoopAgent</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    model<span class="token punctuation">:</span> <span class="token function">openai</span><span class="token punctuation">(</span><span class="token string">"gpt-4o-mini"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    instructions<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>system<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">,</span>
    tools<span class="token punctuation">:</span> <span class="token punctuation">{</span>
      timetool<span class="token punctuation">:</span> getTimeTool<span class="token punctuation">,</span>
      greettool<span class="token punctuation">:</span> greetTool<span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    toolChoice<span class="token punctuation">:</span> <span class="token string">'auto'</span><span class="token punctuation">,</span>
    stopWhen<span class="token punctuation">:</span> <span class="token function">stepCountIs</span><span class="token punctuation">(</span><span class="token number">3</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>You can use this agent as shown below, by calling the <code>generate</code> function and passing the user message in the prompt.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">const</span> <span class="token punctuation">{</span> output <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> myAgent<span class="token punctuation">.</span><span class="token function">generate</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    prompt<span class="token punctuation">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
            role<span class="token punctuation">:</span> <span class="token string">'user'</span><span class="token punctuation">,</span>
            content<span class="token punctuation">:</span> <span class="token string">"Greet Tom Cruise"</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>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>output<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>You should get this output from the agent:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/user-message-generated.png?sfvrsn=3d27d290_2" alt="Hey Tom Cruise, here is the time in ISO format: .." /></p><h2 id="debugging-agent">Debugging Agent</h2><p>You can debug the agent&rsquo;s behavior by inspecting the steps returned during execution. These steps show each model decision and tool call, making it easier to trace how the agent reached its final output.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">const</span> <span class="token punctuation">{</span> output<span class="token punctuation">,</span>steps <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> myAgent<span class="token punctuation">.</span><span class="token function">generate</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    prompt<span class="token punctuation">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
            role<span class="token punctuation">:</span> <span class="token string">'user'</span><span class="token punctuation">,</span>
            content<span class="token punctuation">:</span> <span class="token string">"Greet Tom Cruise"</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>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>steps<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>toolCalls<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>toolName<span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>steps<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The output should include the name of the first <code>toolName</code> alongside metadata of all tools being invoked.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/toolname-output.png?sfvrsn=7fcda56e_2" alt="default step result" /></p><p>As you see from the steps output, you can print result of the tool, input and other details. For example, the below snippet prints the first <code>toolName</code> and the output of second tool.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">const</span> <span class="token punctuation">{</span> output<span class="token punctuation">,</span>steps <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> myAgent<span class="token punctuation">.</span><span class="token function">generate</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    prompt<span class="token punctuation">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
            role<span class="token punctuation">:</span> <span class="token string">'user'</span><span class="token punctuation">,</span>
            content<span class="token punctuation">:</span> <span class="token string">"Greet Tom Cruise"</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>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>steps<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>toolCalls<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>toolName<span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>steps<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>toolResults<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>output<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>You should get the output:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/toolname-message.png?sfvrsn=4bce2eac_2" alt="timetool, message: Hello, Tom Cruise!" /></p><h2 id="agent-loop-control">Agent Loop Control</h2><p>By default, the agent runs for 20 steps, but we are overriding that for three steps by passing a value to <code>stopWhen</code> property.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">const</span> myAgent <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ToolLoopAgent</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token comment">//rest of code</span>
    stopWhen<span class="token punctuation">:</span> <span class="token function">stepCountIs</span><span class="token punctuation">(</span><span class="token number">3</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>By default, an agent runs for up to 20 steps. In each step, the model can either generate a final response or call a tool.</p><p>If the model generates text, the agent finishes. If it calls a tool, the AI SDK executes that tool and feeds the result back to the model.</p><p>To allow the agent to call multiple tools in sequence, we need to increase the <code>stopWhen</code> limit. After each tool execution, the agent starts a new generation step, giving the model another chance to call a tool or produce the final output.</p><p>Each step represents one generation that is either generated text or call to the tool. The loop continues until:</p><ul><li>A finish reasoning other than tool calls is returned, or</li><li>A tool that is invoked does not have an execute function, or</li><li>A tool call needs approval, or</li><li>A stop condition is met</li></ul><p>To stop the loop, you can combine the multiple stop conditions such as:</p><ol><li><code>stepCountIs</code></li><li><code>hasTooCall</code></li><li>custom condition</li></ol><p><code>hasToCall</code> is a built-in stopping condition and stops the agent loop when a particular tool is called. You can combine two stop conditions as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">const</span> myAgent <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ToolLoopAgent</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    model<span class="token punctuation">:</span> <span class="token function">openai</span><span class="token punctuation">(</span><span class="token string">"gpt-4o-mini"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    instructions<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>system<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">,</span>
    tools<span class="token punctuation">:</span> <span class="token punctuation">{</span>
      timetool<span class="token punctuation">:</span> getTimeTool<span class="token punctuation">,</span>
      greettool<span class="token punctuation">:</span> greetTool<span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    toolChoice<span class="token punctuation">:</span> <span class="token string">'auto'</span><span class="token punctuation">,</span>
    stopWhen<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token function">stepCountIs</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span> 
        <span class="token function">hasToolCall</span><span class="token punctuation">(</span><span class="token string">'greettool'</span><span class="token punctuation">)</span>
    <span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><h2 id="agent-to-send-blog-summary">Agent to Send Blog Summary</h2><p>Putting everything together, let&rsquo;s build an agent that fetches a blog post, generates a summary and sends it to a specified email address. We&rsquo;ll use the following libraries:</p><ol><li>Resend &ndash; To send the email. You&rsquo;ll need an API key from Resend to authenticate requests.</li><li>Cheerio &ndash; To parse and extract content from the blog&rsquo;s HTML page.</li></ol><p>Before implementing the agent, install the required dependencies in your project:</p><pre><code>npm install resend
npm install cheerio
</code></pre><p>Once installed, the agent can use Cheerio to scrape the blog content, generate a summary via the model and then use Resend to deliver that summary via email.</p><p>Let&rsquo;s start by defining a tool that extracts content from a given webpage. This tool will fetch the page, parse its HTML and return the relevant information needed for further processing.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> tool<span class="token punctuation">,</span> zodSchema <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'ai'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'zod'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> cheerio <span class="token keyword">from</span> <span class="token string">'cheerio'</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> extractWebpageTool <span class="token operator">=</span> <span class="token function">tool</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  description<span class="token punctuation">:</span> <span class="token string">'Fetches a webpage URL and returns its main text content.'</span><span class="token punctuation">,</span>
  inputSchema<span class="token punctuation">:</span> <span class="token function">zodSchema</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    url<span class="token punctuation">:</span> z<span class="token punctuation">.</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 function">url</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">'Webpage URL'</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>
  execute<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> url <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span>url<span class="token punctuation">,</span> <span class="token punctuation">{</span> headers<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">'User-Agent'</span><span class="token punctuation">:</span> <span class="token string">'Agent/1.0'</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">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>res<span class="token punctuation">.</span>ok<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> success<span class="token punctuation">:</span> <span class="token keyword">false</span><span class="token punctuation">,</span> content<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span> error<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`HTTP </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>res<span class="token punctuation">.</span>status<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> html <span class="token operator">=</span> <span class="token keyword">await</span> res<span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> $ <span class="token operator">=</span> cheerio<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span>html<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'script, style, nav, footer'</span><span class="token punctuation">)</span><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">const</span> content <span class="token operator">=</span> <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'body'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex">/\s+/g</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">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> 15_000<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span> success<span class="token punctuation">:</span> <span class="token keyword">true</span><span class="token punctuation">,</span> url<span class="token punctuation">,</span> content <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">err</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span> success<span class="token punctuation">:</span> <span class="token keyword">false</span><span class="token punctuation">,</span> content<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span> error<span class="token punctuation">:</span> err <span class="token keyword">instanceof</span> <span class="token class-name">Error</span> <span class="token operator">?</span> err<span class="token punctuation">.</span>message <span class="token punctuation">:</span> <span class="token function">String</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token 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>Next let&rsquo;s create a tool to send an email, as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> tool<span class="token punctuation">,</span> zodSchema <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'ai'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'zod'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Resend <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'resend'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> resend <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Resend</span><span class="token punctuation">(</span>'key<span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// your key</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> sendEmailTool <span class="token operator">=</span> <span class="token function">tool</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  description<span class="token punctuation">:</span> <span class="token string">'Sends an email. Pass to and body.'</span><span class="token punctuation">,</span>
  inputSchema<span class="token punctuation">:</span> <span class="token function">zodSchema</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span> to<span class="token punctuation">:</span> z<span class="token punctuation">.</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 function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> body<span class="token punctuation">:</span> z<span class="token punctuation">.</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><span class="token punctuation">)</span><span class="token punctuation">,</span>
  execute<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> to<span class="token punctuation">,</span> body <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> <span class="token punctuation">{</span> data<span class="token punctuation">,</span> error <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> resend<span class="token punctuation">.</span>emails<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      <span class="token keyword">from</span><span class="token punctuation">:</span> <span class="token string">'hello@nomadcoder.ai'</span><span class="token punctuation">,</span>
      to<span class="token punctuation">:</span> <span class="token punctuation">[</span>to<span class="token punctuation">]</span><span class="token punctuation">,</span>
      subject<span class="token punctuation">:</span> <span class="token string">'From Agent'</span><span class="token punctuation">,</span>
      html<span class="token punctuation">:</span> body<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'&lt;'</span><span class="token punctuation">)</span> <span class="token operator">?</span> body <span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`&lt;p&gt;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>body<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex">/\n/g</span><span class="token punctuation">,</span> <span class="token string">'&lt;/p&gt;&lt;p&gt;'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/p&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 keyword">return</span> error <span class="token operator">?</span> <span class="token punctuation">{</span> success<span class="token punctuation">:</span> <span class="token keyword">false</span><span class="token punctuation">,</span> error<span class="token punctuation">:</span> error<span class="token punctuation">.</span>message <span class="token punctuation">}</span> <span class="token punctuation">:</span> <span class="token punctuation">{</span> success<span class="token punctuation">:</span> <span class="token keyword">true</span><span class="token punctuation">,</span> message<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`Sent to </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>to<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Next, combine these two tools and register them with the agent so it can orchestrate their execution as part of its workflow.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">var</span> system <span class="token operator">=</span> <span class="token template-string"><span class="token string">`You are a helpful assistant. For this task you MUST:
1. First call the extractwebpagetool to get the content of the webpage.
2. Create a summary of the webpage content.
3. After that call the sendemail tool to send the email to the recipient.
3. After you have called BOTH tools and received their results, write one short final message that greets the person and includes the time in ISO format (e.g. "Hey DJ, here is the time in ISO format: ...").
Do not skip the tools.`</span></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> myAgent <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ToolLoopAgent</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    model<span class="token punctuation">:</span> <span class="token function">openai</span><span class="token punctuation">(</span><span class="token string">"gpt-4o-mini"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    instructions<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>system<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">,</span>
    tools<span class="token punctuation">:</span> <span class="token punctuation">{</span>
      extractWebpageTool<span class="token punctuation">:</span> extractWebpageTool<span class="token punctuation">,</span>
      senemail<span class="token punctuation">:</span> sendEmailTool<span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    toolChoice<span class="token punctuation">:</span> <span class="token string">'auto'</span><span class="token punctuation">,</span>
    stopWhen<span class="token punctuation">:</span> <span class="token function">stepCountIs</span><span class="token punctuation">(</span><span class="token number">3</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>Next, invoke the agent in loop as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">const</span> <span class="token punctuation">{</span> output<span class="token punctuation">,</span>steps <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> myAgent<span class="token punctuation">.</span><span class="token function">generate</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    prompt<span class="token punctuation">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
            role<span class="token punctuation">:</span> <span class="token string">'user'</span><span class="token punctuation">,</span>
            content<span class="token punctuation">:</span> <span class="token string">"Send summary of https://www.telerik.com/blogs/how-to-use-cursor-modern-angular to debugmode@outlook.com"</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>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>output<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>This agent will send the summary of the given post to the passed email address.</p><h2 id="summary">Summary</h2><p>In this article, we explored how to build an agent using the Vercel AI SDK and implemented a practical example that generates a blog summary and sends it to a specified email address. I hope you found it helpful. Thanks for reading.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">A Guide to Tool Calling with the TypeScript AI SDK</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Learn how to connect your AI applications to the real world using tool calling. This step-by-step guide for TypeScript developers shows you how to use custom functions and provider-native tools like Gemini's url_context with the <a target="_blank" href="https://www.telerik.com/blogs/guide-tool-calling-typescript-ai-sdk">Vercel AI SDK</a>.</p></div></div></aside><img src="https://feeds.telerik.com/link/10827/17307665.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-04-18T12:15:37Z</updated>
    <author>
      <name>Jon Hilton </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17305974/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/10827/17305974.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:3c8c4ee0-cf8c-4226-b0de-9aa709b3a16e</id>
    <title type="text">Top 3 Everyday Angular Tasks That MCP Servers Automate for You</title>
    <summary type="text">Scaffolding, creating UI from ideas and data, iterating and updating. These are things every Angular developer does, and here’s how MCP can help.</summary>
    <published>2026-03-24T21:04:24Z</published>
    <updated>2026-04-18T12:15:37Z</updated>
    <author>
      <name>Alyssa Nicoll </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17305467/top-3-everyday-angular-tasks-mcp-servers-automate"/>
    <content type="text"><![CDATA[<p><span class="featured">Scaffolding, creating UI from ideas and data, iterating and updating. These are things every Angular developer does, and here&rsquo;s how MCP can help. </span></p><p>Angular developers spend a lot of time on repetitive UI tasks like scaffolding components, wiring data into views and adjusting layouts. Or, at least they used to, before the age of AI.</p><p>Now, MCP-powered tools can automate much of that work&mdash;letting coding assistants generate Angular code and tools like Agentic UI Generator turn prompts or data into working UI so developers can move faster.</p><blockquote><p>&ldquo;AI made refactoring and handling technical debt much faster, allowing us to focus on market features. Validating ideas, creating POCs, and writing tests are also areas where we&rsquo;ve seen huge impact. The whole development lifecycle changed, and it opened the door for exploration and innovation.&rdquo;<br />&mdash; Progress Product Team Insight</p></blockquote><p><strong>Model Context Protocol (MCP)</strong> is a way for AI assistants to connect directly to tools and dev environments instead of generating code in isolation.</p><p>Without that connection, AI can only make suggestions based on patterns it has seen before. It doesn&rsquo;t know what Angular version you&rsquo;re using, what components exist in your UI library or what APIs are actually available in your project. (Unless your assistant is built into a full-blown IDE, like <a href="https://www.telerik.com/blogs/how-to-use-cursor-modern-angular" target="_blank">Cursor</a>.)</p><p>Often, with AI, the output might look correct, but developers end up fixing hallucinated APIs or rewriting scaffolding to make it fit their app. MCP closes that gap by giving AI access to real context&mdash;frameworks, component libraries, project structure and tooling. Instead of guessing what code might work, the assistant can generate output grounded in the tools you&rsquo;re actually using.</p><p>So if you love VS Code, for example, but Copilot just isn&rsquo;t cutting it for frontend AI-generated code, this is where MCP can fill the gap.</p><p>This is especially true for frontend work. Angular developers spend a lot of time on repetitive UI tasks like scaffolding components, wiring data into views and configuring layouts. MCP-powered tools can automate much of that groundwork. Coding assistants can generate valid Angular structures, and tools like Agentic UI Generator can turn prompts or data into working UI.</p><p>The result isn&rsquo;t magic code generation&mdash;it&rsquo;s a faster starting point. AI helps developers get moving, while humans still shape the final result.</p><h2 id="task-1-scaffolding-angular-components-faster">Task #1: Scaffolding Angular Components Faster</h2><p>Creating components is one of the most common tasks in Angular development. Even with Angular CLI, developers still need to generate the component, add inputs, wire services and start building the template.</p><p>If your coding assistant is connected to the Progress <strong><a target="_blank" href="https://www.telerik.com/angular-mcp-servers">Kendo UI for Angular MCP server</a></strong>, it understands the components available in your UI library and can generate valid Angular structures using them.</p><p>With an MCP-powered coding assistant, you can start with a simple prompt:</p><pre class=" language-javascript"><code class="prism  language-javascript">#kendo_component_assistant Create a ProductCard Angular component that displays a product image<span class="token punctuation">,</span>
name<span class="token punctuation">,</span> and price using Kendo UI components<span class="token punctuation">.</span>
</code></pre><p>The assistant can generate a working Angular component structure:</p><pre class=" language-javascript"><code class="prism  language-javascript">@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-product-card'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>KENDO_LAYOUT<span class="token punctuation">,</span> NgOptimizedImage<span class="token punctuation">]</span><span class="token punctuation">,</span>
  template<span class="token punctuation">:</span> `
    <span class="token operator">&lt;</span>kendo<span class="token operator">-</span>card <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"product-card"</span> width<span class="token operator">=</span><span class="token string">"100%"</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>img
        kendoCardMedia
        <span class="token punctuation">[</span>ngSrc<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"product().imageUrl"</span>
        <span class="token punctuation">[</span>width<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"product().imageWidth"</span>
        <span class="token punctuation">[</span>height<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"product().imageHeight"</span>
        <span class="token punctuation">[</span>alt<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"product().imageAlt"</span>
      <span class="token operator">/</span><span class="token operator">&gt;</span>

      <span class="token operator">&lt;</span>kendo<span class="token operator">-</span>card<span class="token operator">-</span>body<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>h3 kendoCardTitle<span class="token operator">&gt;</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">product</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>name <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>h3<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>p <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"product-price"</span> <span class="token punctuation">[</span>attr<span class="token punctuation">.</span>aria<span class="token operator">-</span>label<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"'Price: ' + formattedPrice()"</span><span class="token operator">&gt;</span>
          <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">formattedPrice</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span>
        <span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>kendo<span class="token operator">-</span>card<span class="token operator">-</span>body<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>kendo<span class="token operator">-</span>card<span class="token operator">&gt;</span>
    <span class="token operator">...</span>
</code></pre><p>Instead of starting from scratch, developers get a <strong>valid Angular starting point immediately</strong> and can focus on refining the UI.</p><h2 id="task-2-turning-data-into-ui">Task #2: Turning Data Into UI</h2><p>A large portion of frontend work isn&rsquo;t writing complex logic&mdash;it&rsquo;s translating data and ideas into working UI.</p><p>As devs, we are accustomed to taking API responses or product requirements and turn them into forms, dashboards or application layouts. That process usually starts with sketching the structure of the interface and then building the components to support it.</p><p>With the <strong><a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/agentic-ui-generator/getting-started">Angular Agentic UI Generator</a></strong>, you can start that process with a prompt instead.</p><p>Because the tool connects to your UI library through MCP, it understands the components available in your stack and can generate layouts using them. Instead of manually assembling the structure of the page, the generator produces a working Angular layout you can refine.</p><p>For example, you might start with a prompt like this:</p><blockquote><p>#kendo-ui-generator Create a responsive Workflow Composer app layout that includes: a left sidebar that only takes up 1/3 max of the UI for available workflow steps (this is essentially a column that is a list of individual cards/tasks), and main canvas area for building connected flows.</p></blockquote><p>From there, the generator produces a starting UI layout using Kendo UI for Angular components.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/workflow-composer.png?sfvrsn=7250b55a_2" alt="Workflow Composer shows steps for start, webhook trigger, output" /></p><h2 id="task-3-updating-and-iterating-on-ui">Task #3: Updating and Iterating on UI</h2><p>Building the first version of a UI is only the beginning. Most frontend work happens in the iteration phase&mdash;adjusting layouts, adding interactions and refining components as requirements evolve.</p><p>This is another area where MCP-connected assistants can help speed things up. Instead of manually digging through templates and wiring new behavior, developers can describe the change they want and let the assistant update the structure.</p><p>For this last task, I took our generated Workflow Composer app and added drag-and-drop support with a simple prompt:</p><blockquote><p>#kendo_ui_generator let&rsquo;s add drag and drop</p></blockquote><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/ui-generator-add-drag-drop.png?sfvrsn=29ecb3c0_2" alt="kendo_ui_generator let&#39;s add drag and drop" /></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/drag-drop-workflow.gif?sfvrsn=a5876330_1" alt="Workflow Composer now has drag and drop. User adds steps to the workflow in seconds." /></p><p>Rather than rewriting the layout or manually integrating interaction logic, the assistant extends the generated UI and adds the new behavior.</p><p>One thing I&rsquo;ve noticed while experimenting with this workflow is that <strong>single task prompts tend to work best</strong>. Breaking changes into bite-sized requests often produces cleaner results when working with MCP-powered tools and Copilot.</p><h2 id="why-mcp-matters">Why MCP Matters</h2><p>AI coding tools are useful, but without access to your real development environment, they can only generate suggestions based on patterns they&rsquo;ve seen before.</p><p>MCP changes that by connecting AI assistants directly to the tools developers already use. Instead of guessing which components exist or how your project is structured, the assistant can interact with real frameworks, libraries and development workflows.</p><p>That connection is what makes tasks like generating Angular components, creating UI layouts or iterating on interfaces possible with simple prompts. Rather than starting from scratch each time, devs get a working starting point that fits their stack.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Angular and Kendo UI MCP: Making Agents Work for You</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Keep reading: See what&rsquo;s possible when your AI assistant can use your actual tools to perform work for you: The Kendo UI for <a target="_blank" href="https://www.telerik.com/blogs/angular-kendo-ui-mcp-making-agents-work">Angular AI Coding Assistant can connect with the Angular MCP Server</a> in a truly intelligent way.</p></div></div><hr class="u-mb3" /></aside><h2 id="conclusion">Conclusion</h2><p>Angular developers spend a lot of time on repetitive UI work&mdash;scaffolding components, turning data into layouts and iterating on interfaces as requirements evolve.</p><p>MCP-powered tools can help automate much of that groundwork. Coding assistants can generate valid Angular structures, and tools like the <strong>Angular Agentic UI Generator</strong> can turn prompts into working UI layouts that developers can refine and extend.</p><p>If you&rsquo;d like to try it yourself, you can install our MCP servers and learn how to get started with <strong>Coding Assistant</strong> and <strong>Agentic UI Generator</strong> in the documentation.</p><p> <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/installation">Explore the MCP setup guide in the docs.</a></p><img src="https://feeds.telerik.com/link/10827/17305467.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:a8f7f09d-7995-4cb5-801c-72969ae00ceb</id>
    <title type="text">Coding Azure 23: Reading Settings from an App Configuration Service</title>
    <summary type="text">Today, we’ll get the code needed to retrieve the App Configuration service setting values in the application code.</summary>
    <published>2026-03-23T17:50:52Z</published>
    <updated>2026-04-18T12:15:37Z</updated>
    <author>
      <name>Peter Vogel </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17304667/coding-azure-23-reading-settings-app-configuration-service"/>
    <content type="text"><![CDATA[<p><span class="featured">Today, we&rsquo;ll get the code needed to retrieve the App Configuration service setting values in the application code.</span></p><p>In my last post, <a target="_blank" href="https://www.telerik.com/blogs/coding-azure-22-adding-configuration-information-app-configuration-service">Coding Azure 22</a>, I showed how to add settings to an App Configuration service to hold configuration information that needs to be shared among multiple components in a distributed application (the example I used was the name of a queue that would be written to by some frontend application and read from by some backend processor). In this post, I&rsquo;ll look at the code you need to retrieve those setting values in your application code.</p><p>If you&rsquo;ve worked with retrieving information from a .NET configuration file (e.g., the appsettings.json file in an ASP.NET Core application) through the <code>IConfiguration</code> interface, then you&rsquo;re already familiar with most of what you need to do. It&rsquo;s just a matter of integrating your App Configuration service into your configuration settings.</p><p>That means that you can treat your configuration file and your App Configuration service (and, if your application is running in an App Service, your App Service&rsquo;s <a target="_blank" href="https://www.telerik.com/blogs/coding-azure-14-accessing-key-vault-secrets-server-side-application-testing-secret-manager#retrieving-an-environment-variable">Environment Variables</a>) as a single source.</p><p>Having said that, an App Configuration service provides a lot more options than a plain old JSON file or an Environments settings file. You may want to consider making an App Configuration service as your only source for configuration information.</p><h2 id="integrating-your-app-configuration-service">Integrating Your App Configuration Service</h2><p>To enable your application to access your App Configuration service, your application needs two NuGet packages:</p><ul><li>Add Azure.Identity.Web (probably already part of your application&rsquo;s dependencies)</li><li>Microsoft.Extensions.Configuration.AzureAppConfiguration</li></ul><p>You&rsquo;ll then need to update your application&rsquo;s Program.cs file to integrate your App Configuration service into your application&rsquo;s configuration information. Provided you have only one setting for any Key in your service, you just need to call the <code>Configuration</code> object&rsquo;s <code>AddAzureAppConfiguration</code>, passing the URL for your service (as a <code>Uri</code> object) and some credential object. That could be as simple as this code:</p><pre class=" language-csharp"><code class="prism  language-csharp">builder<span class="token punctuation">.</span>Configuration<span class="token punctuation">.</span><span class="token function">AddAzureAppConfiguration</span><span class="token punctuation">(</span>o <span class="token operator">=</span><span class="token operator">&gt;</span>
    o<span class="token punctuation">.</span><span class="token function">Connect</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">"&lt;url for your App Configuration Service&gt;"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> 
    <span class="token keyword">new</span> <span class="token class-name">DefaultAzureCredential</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>   
</code></pre><p>You can retrieve the URL for your service from your App Configuration&rsquo;s Overview page. Using <code>DefaultAzureCredential</code> will enable you to run your code from an App Service using the App Service&rsquo;s Managed Identity and test your code from with Visual Studio or Visual Studio Code (assuming that you&rsquo;ve added the Azure extension to Visual Studio Code).</p><h2 id="retrieving-setting-values">Retrieving Setting Values</h2><p>In an ASP.NET Core application, to retrieve a value from your merged configuration source, you must first retrieve the <code>IConfiguration</code> object from your application&rsquo;s services collection. This example from an ASP.NET controller retrieves the service in the controller&rsquo;s constructor and stores it in a field called <code>config</code>:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">private</span> <span class="token keyword">readonly</span> IConfiguration config<span class="token punctuation">;</span>

 <span class="token keyword">public</span> <span class="token function">Worker</span><span class="token punctuation">(</span>ILogger<span class="token operator">&lt;</span>Worker<span class="token operator">&gt;</span> logger<span class="token punctuation">,</span> IConfiguration config<span class="token punctuation">)</span>
 <span class="token punctuation">{</span>
     <span class="token keyword">this</span><span class="token punctuation">.</span>config <span class="token operator">=</span> config<span class="token punctuation">;</span>        
</code></pre><p>With the <code>IConfiguration</code> object in the config field, you could retrieve the value for a setting with its Key set to &ldquo;QueueName&rdquo; using this code:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">string</span><span class="token operator">?</span> qname <span class="token operator">=</span> config<span class="token punctuation">[</span><span class="token string">"QueueName"</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
</code></pre><p>In a Razor file you can retrieve the <code>IConfiguration</code> object using the <code>inject</code> directive. This code retrieves the <code>IConfiguration</code> object into a field called config and then uses it to retrieve a setting with a Key set to &ldquo;AltText&rdquo;:</p><pre class=" language-razor"><code class="prism  language-razor">@inject IConfiguration config
&hellip;
&lt;img alt='@config ["AltText"]' &hellip;
</code></pre><h2 id="handling-duplicate-key-values">Handling Duplicate Key Values</h2><p>If the Key you specify doesn&rsquo;t exist or there is more than one version of the Key, then both of those sets of code return <code>null</code>. (Because of that, it&rsquo;s a good practice to always check for <code>null</code> after retrieving configuration values.)</p><p>You can have multiple versions of a Key if you&rsquo;ve taken advantage of the App Configuration service&rsquo;s ability to have multiple settings with the same Key, each with a different Label (e.g., &ldquo;production,&rdquo; &ldquo;dev&rdquo;). To avoid retrieving multiple versions of the same key, you&rsquo;ll need to specify which version of any Key you want to retrieve when configuring your application.</p><p>In your Program.cs file, you can specify the version of each Key that you want by configuring <code>AddAzureAppConfiguration</code> through its options object, using the object&rsquo;s <code>Select</code> method. The <code>Select</code> method accepts two parameters:</p><ul><li><code>KeyFilter.Any</code></li><li>Either
 <ul><li><code>LabelFiler.Null</code> which matches to Labels that have no value</li><li>A string value to compare Labels to</li></ul></li></ul><p>You can use multiple <code>Select</code>s when configuring <code>AddAzureAppConfiguration</code>. Multiple <code>Select</code>s will not result in duplicate Keys because values retrieved by later <code>Select</code> methods overwrite values retrieved in earlier <code>Select</code>s.</p><p>The following example is typical code in a Program.cs in the production version of your application:</p><ul><li>The first <code>Select</code> retrieves settings that don&rsquo;t have a Label (i.e., settings that are to be used in any environment)</li><li>The second <code>Select</code> retrieves settings that have their Label set to &ldquo;production&rdquo;</li></ul><pre class=" language-csharp"><code class="prism  language-csharp">builder<span class="token punctuation">.</span>Configuration<span class="token punctuation">.</span><span class="token function">AddAzureAppConfiguration</span><span class="token punctuation">(</span>o <span class="token operator">=</span><span class="token operator">&gt;</span>
<span class="token punctuation">{</span>
   o<span class="token punctuation">.</span><span class="token function">Connect</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">"&lt;url for your App Configuration Service&gt;"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> 
             <span class="token keyword">new</span> <span class="token class-name">DefaultAzureCredential</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">Select</span><span class="token punctuation">(</span>KeyFilter<span class="token punctuation">.</span>Any<span class="token punctuation">,</span> LabelFilter<span class="token punctuation">.</span>Null<span class="token punctuation">)</span>
           <span class="token punctuation">.</span><span class="token function">Select</span><span class="token punctuation">(</span>KeyFilter<span class="token punctuation">.</span>Any<span class="token punctuation">,</span> <span class="token string">"production"</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>Order matters here: If there is a Key that has both a version with no Label <em>and</em> a version with a Label set to "production,&rdquo; the &ldquo;production&rdquo; version will overwrite the values from the version without a Label because the &ldquo;production&rdquo; version is selected second.</p><p>You can make this code more portable by replacing the hard-coded &ldquo;production&rdquo; string with a call to <code>builder.Environment.EnvironmentName</code> (provided, of course, that your environment names match the Labels you&rsquo;re using in your App Configuration service). Be aware: Labels are case-sensitive: &ldquo;Production&rdquo; is not a match to &ldquo;production.&rdquo;</p><p>You have a different issue if Keys in your App Configuration file duplicate settings in either your application&rsquo;s configuration file (e.g., appsettings.json) or in an App Service&rsquo;s Environment Variables (all of which are merged into <code>IConfiguration</code>). Those matching keys form a hierarchy: App Configuration values override Environment Variables which, in turn, override configuration file settings. The danger here is that you may lose a setting in your configuration file because it&rsquo;s accidentally overridden by a matching Key in your App Configuration service.</p><h3 id="handling-data-type">Handling Data Type</h3><p>By default, all configuration values are treated as strings. You can use the <code>config</code> object&rsquo;s <code>GetValue</code> method to handle conversions and, as a bonus, provide a default value.</p><p>The <code>GetValue</code> method is a generic method, which lets you specify the data type of the value you&rsquo;re retrieving. You pass it the Key of the setting to retrieve and, optionally, a default value to return if the Key can&rsquo;t be found or if the Key can&rsquo;t be converted.</p><p>This example converts the setting&rsquo;s value to an integer or returns -1 if the setting isn&rsquo;t found or can&rsquo;t be converted:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">int</span><span class="token operator">?</span> <span class="token keyword">value</span> <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token generic-method function">GetValue<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">"QueueLength"</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><h2 id="retrieving-multiple-settings">Retrieving Multiple Settings</h2><p>If you used the recommended naming convention to group related Keys in your settings, then you retrieve those settings together. These sample Keys group together the <code>WebServiceUrl</code> and <code>AuthorizationKey*n*</code> settings by prefixing them with &ldquo;SalesOrder&rdquo;:</p><p><code>SalesOrder:WebServiceUrl</code><br /><code>SalesOrder:AuthorizationKey1</code><br /><code>SalesOrder:AuthorizationKey2</code>
</p><p>You can retrieve their values individually with code like this:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">string</span> url <span class="token operator">=</span> config<span class="token punctuation">[</span><span class="token string">"SalesOrder:WebServiceUrl"</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">string</span> authKey <span class="token operator">=</span> config<span class="token punctuation">[</span><span class="token string">"SalesOrder:AuthorizationKey1"</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
</code></pre><p>However, you can also retrieve all the <code>SalesOrder</code> prefixed settings as a single group. You have two options here. One approach treats the <code>SalesOrder</code> settings as a class with properties; the other approach treats the <code>SalesOrder</code> settings as nested arrays.</p><h3 id="retrieving-a-section-as-a-class">Retrieving a Section as a Class</h3><p>The first step in treating grouped settings as a class is to define a class with property names that match the members of the section (the class name doesn&rsquo;t matter but the property names, while not case sensitive, must match the names of the child settings). A typical class for my <code>SalesOrder</code> settings might look like this:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">internal</span> <span class="token keyword">class</span> <span class="token class-name">SalesOrderSection</span>
<span class="token punctuation">{</span>
   <span class="token keyword">public</span> <span class="token keyword">string</span> webServiceUrl <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> authorizationKey1 <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> authorizationKey2 <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 punctuation">}</span>
</code></pre><p>Then, in your Program.cs file, as part of configuring your App Configuration service, you use the <code>Configuration</code> object&rsquo;s <code>GetSection</code> method to retrieve the SalesOrder prefixed settings as a section. You then use the <code>Services</code> object&rsquo;s <code>Configure</code> method to both load that section into your class and add that class to your application&rsquo;s Services collection.</p><p>Typical code would look like this:</p><pre class=" language-csharp"><code class="prism  language-csharp">IConfiguration soSection <span class="token operator">=</span> builder<span class="token punctuation">.</span>Configuration
                                                                        <span class="token punctuation">.</span><span class="token function">GetSection</span><span class="token punctuation">(</span><span class="token string">"SalesOrder"</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">Configure<span class="token punctuation">&lt;</span>SalesOrderSection<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span>soSection<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>That code would create an <code>IOptions&lt;SalesOrderSection&gt;</code> object and add it to your application&rsquo;s <code>Services</code> collection. The <code>Value</code> property of that <code>IOptions</code> object would hold the class with the SalesOrder section&rsquo;s values.</p><p>Typical code in one of your application&rsquo;s components to pull that object from the Services collection and retrieve the values stored in it would look like this:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">private</span> SalesOrderSection soSettings<span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token function">HomeController</span><span class="token punctuation">(</span>IOptions<span class="token operator">&lt;</span>SalesOrderSection<span class="token operator">&gt;</span> soSettings<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>soSettings <span class="token operator">=</span> soSettings<span class="token punctuation">.</span>Value<span class="token punctuation">;</span>    
    <span class="token keyword">string</span> url <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>soSettings<span class="token punctuation">.</span>webServiceUrl<span class="token punctuation">;</span>
</code></pre><h3 id="retrieving-a-section-as-an-array">Retrieving a Section as an Array</h3><p>Treating the SalesOrder prefixed settings as an array is more flexible but require more code. With this approach, instead of working in your Program.cs file, you use the <code>IConfiguration</code> object&rsquo;s <code>GetSection</code> method in your application where you would retrieve individual values.</p><p>The <code>GetSection</code> method, when passed the prefix that defines your section returns an <code>IConfigurationSection</code> object. You then use that section object&rsquo;s <code>GetChildren</code> method to convert all the settings in the section into an array of <code>IConfigurationSection</code> objects, each of which has a <code>Key</code> and a <code>Value</code> property (and a <code>GetChildren</code> method if your settings have their own nested settings).</p><p>This approach can be especially useful if your settings consist of repeated values because you can loop through the array without having to know how many repeated values there are.</p><p>This sample code loops through my <code>SalesOrder</code> settings looking for my <code>Authorization</code> keys:</p><pre class=" language-csharp"><code class="prism  language-csharp">IConfigurationSection secSO <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token function">GetSection</span><span class="token punctuation">(</span><span class="token string">"SalesOrder"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
IEnumerable<span class="token operator">&lt;</span>IConfigurationSection<span class="token operator">&gt;</span> childrenSO <span class="token operator">=</span> secSO<span class="token punctuation">.</span><span class="token function">GetChildren</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">string</span><span class="token operator">?</span> key <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">foreach</span> <span class="token punctuation">(</span>IConfigurationSection childSo <span class="token keyword">in</span> childrenSO<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span> childSO<span class="token punctuation">.</span>Key<span class="token punctuation">.</span><span class="token function">StartsWith</span><span class="token punctuation">(</span><span class="token string">"Auth"</span><span class="token punctuation">)</span>  <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
         key <span class="token operator">=</span> childSO<span class="token punctuation">.</span>Value<span class="token punctuation">;</span>
       &hellip;process authorization key&hellip;
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Alternatively, you can use LINQ to retrieve specific values, as this example does by using the child object&rsquo;s Key property:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">string</span><span class="token operator">?</span> <span class="token keyword">value</span> <span class="token operator">=</span> childrenSO<span class="token punctuation">.</span><span class="token function">FirstOrDefault</span><span class="token punctuation">(</span>c <span class="token operator">=</span><span class="token operator">&gt;</span> c<span class="token punctuation">.</span>Key <span class="token operator">==</span> <span class="token string">"WebServiceUrl"</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">.</span>Value<span class="token punctuation">;</span>
</code></pre><h2 id="retrieving-json-settings">Retrieving JSON Settings</h2><p>If the value of your setting is a JSON document and you&rsquo;ve set the Content type property of the setting to <code>application/json</code>, then you can treat the JSON document as if it were a section.</p><p>I could have, for example, created a setting with a Key set to &ldquo;SalesOrder&rdquo; and put this JSON document in it (which would also let me define my authorization keys as an array):</p><pre class=" language-json"><code class="prism  language-json"><span class="token punctuation">{</span>
   <span class="token string">"WebServiceUrl"</span><span class="token punctuation">:</span><span class="token string">"https://&hellip;"</span><span class="token punctuation">,</span>
   <span class="token string">"AuthorizationKeys"</span><span class="token punctuation">:</span>   <span class="token punctuation">[</span>
                                                    <span class="token string">"a1&hellip;41"</span><span class="token punctuation">,</span>
                                                     <span class="token string">"4b..ff"</span>
                                                 <span class="token punctuation">]</span>
<span class="token punctuation">}</span>
</code></pre><p>I can then retrieve individual values as if they were configuration settings in my service using code like this:</p><pre class=" language-json"><code class="prism  language-json">string<span class="token operator">?</span> url <span class="token operator">=</span> config<span class="token punctuation">[</span><span class="token string">"SalesOrder:url"</span><span class="token punctuation">]</span>
string<span class="token operator">?</span> authkey1 <span class="token operator">=</span> config<span class="token punctuation">[</span><span class="token string">"SalesOrder:AuthorizationKeys:0"</span><span class="token punctuation">]</span>
string<span class="token operator">?</span> authkey2 <span class="token operator">=</span> config<span class="token punctuation">[</span><span class="token string">"SalesOrder:AuthorizationKeys:1"</span><span class="token punctuation">]</span>
</code></pre><p>You can also use the <code>IConfigurationSection</code> object with the <code>GetSection</code> and <code>GetChildren</code> methods to process your JSON document as I described earlier.</p><h2 id="retrieving-key-vault-references">Retrieving Key Vault References</h2><p>If you are using Key Vault references in your settings, you&rsquo;ll need to configure your App Configuration&rsquo;s service in your application&rsquo;s Program.cs file to grant permission to access the vault at runtime.</p><p>The <code>AddAzureAppConfiguration</code>&rsquo;s options object has a <code>ConfigureKeyVault</code> method that accepts an options object. You need to pass that options object&rsquo;s <code>SetCredential</code> method the credentials that allow access to the Key Vault used in the Key Vault reference. Using <code>DefaultAzureCredential</code> will pick up your credentials in Visual Studio or Visual Studio Code for testing purposes and, at runtime, the Managed Identity assigned to the App Service hosting your application in the cloud.</p><p>This code would pick up the default credentials and use them for any Key Vault references:</p><pre class=" language-csharp"><code class="prism  language-csharp">builder<span class="token punctuation">.</span>Configuration<span class="token punctuation">.</span><span class="token function">AddAzureAppConfiguration</span><span class="token punctuation">(</span>o <span class="token operator">=</span><span class="token operator">&gt;</span>
<span class="token punctuation">{</span>
    o<span class="token punctuation">.</span><span class="token function">ConfigureKeyVault</span><span class="token punctuation">(</span>kvo <span class="token operator">=</span><span class="token operator">&gt;</span>
    <span class="token punctuation">{</span>
        kvo<span class="token punctuation">.</span><span class="token function">SetCredential</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">DefaultAzureCredential</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>
   o<span class="token punctuation">.</span><span class="token function">Connect</span><span class="token punctuation">(</span>&hellip;
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>You can then retrieve the unencrypted value from the Key Vault like any other setting just by using the setting&rsquo;s Key like any other configuration setting:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">string</span><span class="token operator">?</span> <span class="token keyword">value</span> <span class="token operator">=</span> config<span class="token punctuation">[</span><span class="token string">"AuthorizationKey"</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
</code></pre><p>If you&rsquo;re using multiple Key Vaults, the credentials you provide to the <code>ConfigureKeyVault</code> options object will be used for all the Key Vaults. If your Key Vaults require different credentials, you can use that options object&rsquo;s <code>SetSecretResolver</code> method to specify different sets of credentials for different Key Vaults.</p><h2 id="retrieving-snapshots">Retrieving Snapshots</h2><p>If you&rsquo;ve created an App Configuration snapshot to hold a collection of settings, you must configure the <code>AddAzureAppConfiguration</code>&rsquo;s options object to select the snapshot you want to use. That&rsquo;s done through the options object&rsquo;s <code>SelectSnapshot</code> method, passing the Key for your Snapshot Reference setting (i.e., <em>not</em> the name of the snapshot itself). Be aware: If the snapshot can&rsquo;t be found, no exception is raised.</p><p>Your snapshot&rsquo;s settings are merged with the rest of your service&rsquo;s settings. This can result in duplicate Keys (e.g., there&rsquo;s a setting with a Key of &ldquo;QueueName&rdquo; in both your configuration settings and in the snapshot). If that happens, the <em>last</em> entry in the configuration settings list overrides any earlier settings, regardless of where the setting comes from.</p><p>This means that if you want to have your snapshot&rsquo;s settings to always override your configuration settings then you should give your Snapshot References names that appear late in the alphabet (e.g., begin all your Snapshot reference Key values with &ldquo;x-&rdquo;).</p><p>Because snapshots are intended to provide a history of revisions made to your settings, you can not replace or edit a snapshot. However, you can change the snapshot used by a Snapshot Reference in your configuration. So, if you want to change the settings used by an existing Snapshot Reference in your configuration settings, then you must:</p><ol><li>Create a new snapshot</li><li>Edit your Snapshot Reference to point to the new snapshot</li></ol><h2 id="keeping-up-to-date">Keeping Up to Date</h2><p>With the code so far, if the value in a setting in your App Configuration service is changed while your application is running, your application won&rsquo;t pick up the change.</p><p>If you want to keep your application using the current version of the settings in your App Configuration service (or, at least, one that isn&rsquo;t very far out of date), then you should configure the service to refresh its values at some interval. You can do that by using the <code>AddAzurAppConfiguration</code>&rsquo;s options object and calling its <code>ConfigureRefresh</code> method, passing a lambda expression that calls the <code>SetCacheExpiration</code> method (that method accepts a <code>TimeSpan</code> object).</p><p>The code for doing that is probably easier to understand than the explanation. Here&rsquo;s some code that configures the configuration service to refresh its values every 10 minutes:</p><pre class=" language-csharp"><code class="prism  language-csharp">builder<span class="token punctuation">.</span>Configuration<span class="token punctuation">.</span><span class="token function">AddAzureAppConfiguration</span><span class="token punctuation">(</span>o <span class="token operator">=</span><span class="token operator">&gt;</span>
<span class="token punctuation">{</span>
o<span class="token punctuation">.</span><span class="token function">ConfigureRefresh</span><span class="token punctuation">(</span>ropt <span class="token operator">=</span><span class="token operator">&gt;</span>
        ropt<span class="token punctuation">.</span><span class="token function">SetCacheExpiration</span><span class="token punctuation">(</span>TimeSpan<span class="token punctuation">.</span><span class="token function">FromMinutes</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>For this to be effective, though, in your code you must always retrieve your configuration values from the <code>IConfiguration</code> object. If, for example, you store a string value from the <code>IConfiguration</code> object in a field in your application, that field <em>won&rsquo;t</em> be updated when your service is refreshed.</p><h2 id="handling-more-complex-scenarios">Handling More Complex Scenarios</h2><p>If you find that you can&rsquo;t do what you want by merging your App Configuration service into the rest of your configuration sources, you can create a <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.data.appconfiguration.configurationclient?view=azure-dotnet"><code>ConfigurationClient</code></a> object). The <code>ConfigurationClient</code> object provides methods for managing your App Configuration store, including adding and removing settings and snapshots.</p><p>More relevant to this post, the <code>ConfigurationClient</code> also provides <code>GetConfigurationSetting</code> and <code>GetConfigurationSettingForSnapshot</code> methods with multiple overloads that allow you to retrieve a value by any combination of Key, Label and date/time.</p><p>This code, for example, retrieves a complete setting by specifying both the Key and the Label:</p><pre class=" language-csharp"><code class="prism  language-csharp">ConfigurationClient cc <span class="token operator">=</span> <span class="token keyword">new</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://whconfig.azconfig.io"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                              <span class="token keyword">new</span> <span class="token class-name">DefaultAzureCredential</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
ConfigurationSetting cs <span class="token operator">=</span> cc<span class="token punctuation">.</span><span class="token function">GetConfigurationSettingAsync</span><span class="token punctuation">(</span><span class="token string">"QueueName"</span><span class="token punctuation">,</span> <span class="token string">"production"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>And that wraps up the App Configuration service! While App Configuration is essential for distributed applications, its integration with Key Vaults, its support Snapshots and its ability to be automatically refreshed all make it an attractive replacement, I think, for storing configuration information even for standalone applications.</p><img src="https://feeds.telerik.com/link/10827/17304667.gif" height="1" width="1"/>]]></content>
  </entry>
</feed>
