<?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</feedpress:newsletterId>
  <link rel="hub" href="https://feedpress.superfeedr.com/"/>
  <logo>https://static.feedpress.com/logo/telerik-blogs-5aafd3c47efc3.jpg</logo>
  <title type="text">Telerik Blogs</title>
  <subtitle type="text">The official blog of Progress Telerik - expert articles and tutorials for developers.</subtitle>
  <id>uuid:a99235c1-6bd6-4250-9cae-50e6884a658e;id=5205</id>
  <updated>2026-04-06T02:18:19Z</updated>
  <link rel="alternate" href="https://www.telerik.com/"/>
  <link rel="self" type="application/atom+xml" href="https://feeds.telerik.com/blogs"/>
  <entry>
    <id>urn:uuid:6480f9af-1aef-43f5-959f-cab45ab104fc</id>
    <title type="text">Getting Started with the .NET MAUI Speech-to-Text Button Control</title>
    <summary type="text">Add speech-to-text options to your note-taking, chat, meeting or many other types of apps, so your users can skip manual typing in your .NET MAUI app.</summary>
    <published>2026-04-02T19:58:04Z</published>
    <updated>2026-04-06T02:18:19Z</updated>
    <author>
      <name>Héctor Pérez </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/getting-started-net-maui-speech-to-text-button-control"/>
    <content type="text"><![CDATA[<p><span class="featured">Add speech-to-text options to your note-taking, chat, meeting or many other types of apps, so your users can skip manual typing in your .NET MAUI app.</span></p><p>For several years, a common problem for mobile device users has been typing text quickly. Although innovative features such as swipe typing and word autocompletion have been implemented, undoubtedly one of the most comfortable methods remains voice dictation.</p><p>In .NET MAUI, you can take advantage of the Progress Telerik UI for <a target="_blank" href="https://www.telerik.com/maui-ui/speech-to-text-button">.NET MAUI SpeechToTextButton</a> control, which allows converting speech to text. Let&rsquo;s see how to use it in your own .NET MAUI apps!</p><h2 id="getting-to-know-the-telerik-speechtotextbutton-control-for-.net-maui">Getting to Know the Telerik SpeechToTextButton Control for .NET MAUI</h2><p>The SpeechToTextButton control uses platform-specific voice recognition services to perform speech-to-text conversion, including <a target="_blank" href="https://www.telerik.com/maui-ui/documentation/controls/speechtotextbutton/winui-support">WinUI</a>. The structure of the control is simple, and it is based on a button composed of a <strong>SpeechToTextButton Content</strong> and a <strong>SpeechToTextButton</strong>, which you can see in the following image:</p><p><img src="https://www.telerik.com/maui-ui/documentation/assets/e12eb57a64e50c12e588881ba7414605/speechtotextbutton-visual-structure.png" alt="Diagram showing the structure of Telerik’s SpeechToTextButton control for .NET MAUI" /></p><p>Some possible use cases for the control are:</p><ul><li>Voice note-taking</li><li>Chat applications</li><li>Voice search</li><li>Command control via voice</li><li>Meeting transcription</li><li>Among many others</li></ul><p>In reality, the range of use cases is quite large. Now let&rsquo;s analyze the control in more depth.</p><h2 id="creating-a-practical-case">Creating a Practical Case</h2><p>Let&rsquo;s start by creating a demo application, which will help us see the different features of the speech-to-text control. The idea of the application is to be a personal note-taking app that allows actions like editing text, saving notes and sharing them.</p><p>For this example, we&rsquo;ll use the <strong>CommunityToolkit.Mvvm</strong> package, which allows for rapid creation of view models. Below, I show you the initial code for the application in case you want to replicate it, which is as follows:</p><p><strong>TextEditorPage.xaml</strong>:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span>
    <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>20<span class="token punctuation">"</span></span>
    <span class="token attr-name">RowDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Auto, Auto, *, Auto<span class="token punctuation">"</span></span>
    <span class="token attr-name">RowSpacing</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>16<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>

    <span class="token comment">&lt;!--  Header Section  --&gt;</span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Label</span>
        <span class="token attr-name">FontAttributes</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">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>28<span class="token punctuation">"</span></span>
        <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Fast Note<span class="token punctuation">"</span></span>
        <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#1A1A2E<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>

    <span class="token comment">&lt;!--  Status Bar  --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Border</span>
        <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
        <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>16,12<span class="token punctuation">"</span></span>
        <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#F3F4F6<span class="token punctuation">"</span></span>
        <span class="token attr-name">StrokeShape</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>RoundRectangle 12<span class="token punctuation">"</span></span>
        <span class="token attr-name">StrokeThickness</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span> <span class="token attr-name">ColumnDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Auto, *, Auto<span class="token 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">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span>
                <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>12<span class="token punctuation">"</span></span>
                <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding CharacterCount}<span class="token punctuation">"</span></span>
                <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#9CA3AF<span class="token punctuation">"</span></span>
                <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Grid</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Border</span><span class="token punctuation">&gt;</span></span>

    <span class="token comment">&lt;!--  Main Editor Area  --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Border</span>
        <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span>
        <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span>
        <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#FFFFFF<span class="token punctuation">"</span></span>
        <span class="token attr-name">Stroke</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#E5E7EB<span class="token punctuation">"</span></span>
        <span class="token attr-name">StrokeShape</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>RoundRectangle 16<span class="token punctuation">"</span></span>
        <span class="token attr-name">StrokeThickness</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span> <span class="token attr-name">RowDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*, Auto<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Editor</span>
                <span class="token attr-name"><span class="token namespace">x:</span>Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>MainEditor<span class="token punctuation">"</span></span>
                <span class="token attr-name">Margin</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>16<span class="token punctuation">"</span></span>
                <span class="token attr-name">AutoSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>TextChanges<span class="token punctuation">"</span></span>
                <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Transparent<span class="token punctuation">"</span></span>
                <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>16<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>Start typing or use voice input...<span class="token punctuation">"</span></span>
                <span class="token attr-name">PlaceholderColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#9CA3AF<span class="token punctuation">"</span></span>
                <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding EditorText, Mode=TwoWay}<span class="token punctuation">"</span></span>
                <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#1F2937<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>

            <span class="token comment">&lt;!--  Editor Toolbar  --&gt;</span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Border</span>
                <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
                <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>12,0<span class="token punctuation">"</span></span>
                <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#F9FAFB<span class="token punctuation">"</span></span>
                <span class="token attr-name">HeightRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>56<span class="token punctuation">"</span></span>
                <span class="token attr-name">StrokeThickness</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span> <span class="token attr-name">ColumnDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*, Auto, Auto<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                    <span class="token comment">&lt;!--  Word Count  --&gt;</span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>VerticalStackLayout</span> <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Label</span>
                            <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>12<span class="token punctuation">"</span></span>
                            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding WordCount}<span class="token punctuation">"</span></span>
                            <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#6B7280<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>VerticalStackLayout</span><span class="token punctuation">&gt;</span></span>

                    <span class="token comment">&lt;!--  Clear Button  --&gt;</span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Button</span>
                        <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
                        <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>12,8<span class="token punctuation">"</span></span>
                        <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Transparent<span class="token punctuation">"</span></span>
                        <span class="token attr-name">BorderWidth</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span>
                        <span class="token attr-name">Command</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding ClearTextCommand}<span class="token punctuation">"</span></span>
                        <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>14<span class="token punctuation">"</span></span>
                        <span class="token attr-name">IsEnabled</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding HasText}<span class="token punctuation">"</span></span>
                        <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Clear<span class="token punctuation">"</span></span>
                        <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#EF4444<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>

                    <span class="token comment">&lt;!--  Copy Button  --&gt;</span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Button</span>
                        <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span>
                        <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>12,8<span class="token punctuation">"</span></span>
                        <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Transparent<span class="token punctuation">"</span></span>
                        <span class="token attr-name">BorderWidth</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span>
                        <span class="token attr-name">Command</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding CopyTextCommand}<span class="token punctuation">"</span></span>
                        <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>14<span class="token punctuation">"</span></span>
                        <span class="token attr-name">IsEnabled</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding HasText}<span class="token punctuation">"</span></span>
                        <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Copy<span class="token punctuation">"</span></span>
                        <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#3B82F6<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Border</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Border</span><span class="token punctuation">&gt;</span></span>

    <span class="token comment">&lt;!--  Quick Actions  --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span>
        <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>3<span class="token punctuation">"</span></span>
        <span class="token attr-name">ColumnDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*, *, *<span class="token punctuation">"</span></span>
        <span class="token attr-name">ColumnSpacing</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Button</span>
            <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#E5E7EB<span class="token punctuation">"</span></span>
            <span class="token attr-name">BorderWidth</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span>
            <span class="token attr-name">Command</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding NewDocumentCommand}<span class="token punctuation">"</span></span>
            <span class="token attr-name">CornerRadius</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">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>14<span class="token punctuation">"</span></span>
            <span class="token attr-name">HeightRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>44<span class="token punctuation">"</span></span>
            <span class="token attr-name">IsEnabled</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding HasText}<span class="token punctuation">"</span></span>
            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>New<span class="token punctuation">"</span></span>
            <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#374151<span class="token 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">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
            <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#10B981<span class="token punctuation">"</span></span>
            <span class="token attr-name">BorderWidth</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span>
            <span class="token attr-name">Command</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding SaveTextCommand}<span class="token punctuation">"</span></span>
            <span class="token attr-name">CornerRadius</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">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>14<span class="token punctuation">"</span></span>
            <span class="token attr-name">HeightRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>44<span class="token punctuation">"</span></span>
            <span class="token attr-name">IsEnabled</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding HasText}<span class="token punctuation">"</span></span>
            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Save<span class="token punctuation">"</span></span>
            <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#FFFFFF<span class="token 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">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span>
            <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#8B5CF6<span class="token punctuation">"</span></span>
            <span class="token attr-name">BorderWidth</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span>
            <span class="token attr-name">Command</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding ShareTextCommand}<span class="token punctuation">"</span></span>
            <span class="token attr-name">CornerRadius</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">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>14<span class="token punctuation">"</span></span>
            <span class="token attr-name">HeightRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>44<span class="token punctuation">"</span></span>
            <span class="token attr-name">IsEnabled</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding HasText}<span class="token punctuation">"</span></span>
            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Share<span class="token punctuation">"</span></span>
            <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#FFFFFF<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>
</code></pre><p><strong>TextEditorPage.xaml.cs</strong>:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">partial</span> <span class="token keyword">class</span> <span class="token class-name">TextEditorPage</span> <span class="token punctuation">:</span> ContentPage
<span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">readonly</span> TextEditorViewModel _viewModel<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token function">TextEditorPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token function">InitializeComponent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        _viewModel <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TextEditorViewModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        BindingContext <span class="token operator">=</span> _viewModel<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p><strong>TextEditorViewModel.cs</strong>:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">partial</span> <span class="token keyword">class</span> <span class="token class-name">TextEditorViewModel</span> <span class="token punctuation">:</span> ObservableObject
<span class="token punctuation">{</span>
    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token punctuation">[</span><span class="token function">NotifyPropertyChangedFor</span><span class="token punctuation">(</span><span class="token function">nameof</span><span class="token punctuation">(</span>CharacterCount<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token punctuation">[</span><span class="token function">NotifyPropertyChangedFor</span><span class="token punctuation">(</span><span class="token function">nameof</span><span class="token punctuation">(</span>WordCount<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token punctuation">[</span><span class="token function">NotifyPropertyChangedFor</span><span class="token punctuation">(</span><span class="token function">nameof</span><span class="token punctuation">(</span>HasText<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">string</span> _editorText <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>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">string</span> _statusText <span class="token operator">=</span> <span class="token string">"Ready"</span><span class="token punctuation">;</span>

    <span class="token punctuation">[</span>ObservableProperty<span class="token punctuation">]</span>
    <span class="token keyword">private</span> Color _statusColor <span class="token operator">=</span> Colors<span class="token punctuation">.</span>Gray<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">string</span> CharacterCount <span class="token operator">=</span><span class="token operator">&gt;</span> $<span class="token string">"{EditorText?.Length ?? 0} characters"</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">string</span> WordCount
    <span class="token punctuation">{</span>
        <span class="token keyword">get</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">int</span> words <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>EditorText<span class="token punctuation">)</span>
                <span class="token operator">?</span> <span class="token number">0</span>
                <span class="token punctuation">:</span> EditorText<span class="token punctuation">.</span><span class="token function">Split</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">' '</span><span class="token punctuation">,</span> <span class="token string">'\n'</span><span class="token punctuation">,</span> <span class="token string">'\r'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> StringSplitOptions<span class="token punctuation">.</span>RemoveEmptyEntries<span class="token punctuation">)</span><span class="token punctuation">.</span>Length<span class="token punctuation">;</span>
            <span class="token keyword">return</span> $<span class="token string">"{words} words"</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">bool</span> HasText <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token operator">!</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>EditorText<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token preprocessor property">#<span class="token directive keyword">region</span> Commands</span>

    <span class="token punctuation">[</span>RelayCommand<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">ClearText</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        EditorText <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 function">UpdateStatus</span><span class="token punctuation">(</span><span class="token string">"Text cleared"</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token punctuation">[</span>RelayCommand<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">async</span> Task <span class="token function">CopyTextAsync</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>HasText<span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>

        <span class="token keyword">await</span> Clipboard<span class="token punctuation">.</span>Default<span class="token punctuation">.</span><span class="token function">SetTextAsync</span><span class="token punctuation">(</span>EditorText<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">UpdateStatus</span><span class="token punctuation">(</span><span class="token string">"Copied to clipboard"</span><span class="token punctuation">,</span> <span class="token string">"#10B981"</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><span class="token number">2000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">UpdateStatus</span><span class="token punctuation">(</span><span class="token string">"Ready"</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token punctuation">[</span>RelayCommand<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">async</span> Task <span class="token function">NewDocumentAsync</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>HasText<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>Application<span class="token punctuation">.</span>Current<span class="token operator">?</span><span class="token punctuation">.</span>Windows<span class="token punctuation">.</span><span class="token function">FirstOrDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">.</span>Page <span class="token keyword">is</span> Page page<span class="token punctuation">)</span>
            <span class="token punctuation">{</span>
                <span class="token keyword">bool</span> confirm <span class="token operator">=</span> <span class="token keyword">await</span> page<span class="token punctuation">.</span><span class="token function">DisplayAlertAsync</span><span class="token punctuation">(</span><span class="token string">"New Document"</span><span class="token punctuation">,</span>
                    <span class="token string">"Do you want to create a new document? Current text will be lost."</span><span class="token punctuation">,</span>
                    <span class="token string">"Yes"</span><span class="token punctuation">,</span> <span class="token string">"No"</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>confirm<span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>

        EditorText <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 function">UpdateStatus</span><span class="token punctuation">(</span><span class="token string">"New document created"</span><span class="token punctuation">,</span> <span class="token string">"#10B981"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token punctuation">[</span>RelayCommand<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">async</span> Task <span class="token function">SaveTextAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">var</span> page <span class="token operator">=</span> Application<span class="token punctuation">.</span>Current<span class="token operator">?</span><span class="token punctuation">.</span>Windows<span class="token punctuation">.</span><span class="token function">FirstOrDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">.</span>Page<span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>page <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>HasText<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">await</span> page<span class="token punctuation">.</span><span class="token function">DisplayAlertAsync</span><span class="token punctuation">(</span><span class="token string">"Save"</span><span class="token punctuation">,</span> <span class="token string">"There is no text to save."</span><span class="token punctuation">,</span> <span class="token string">"OK"</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 punctuation">}</span>

        <span class="token keyword">try</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">string</span> fileName <span class="token operator">=</span> $<span class="token string">"VoiceNote_{DateTime.Now:yyyyMMdd_HHmmss}.txt"</span><span class="token punctuation">;</span>
            <span class="token keyword">string</span> filePath <span class="token operator">=</span> Path<span class="token punctuation">.</span><span class="token function">Combine</span><span class="token punctuation">(</span>FileSystem<span class="token punctuation">.</span>AppDataDirectory<span class="token punctuation">,</span> fileName<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">await</span> File<span class="token punctuation">.</span><span class="token function">WriteAllTextAsync</span><span class="token punctuation">(</span>filePath<span class="token punctuation">,</span> EditorText<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token function">UpdateStatus</span><span class="token punctuation">(</span><span class="token string">"Document saved"</span><span class="token punctuation">,</span> <span class="token string">"#10B981"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">await</span> page<span class="token punctuation">.</span><span class="token function">DisplayAlertAsync</span><span class="token punctuation">(</span><span class="token string">"Saved"</span><span class="token punctuation">,</span> $<span class="token string">"Document saved as {fileName}"</span><span class="token punctuation">,</span> <span class="token string">"OK"</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>
            <span class="token keyword">await</span> page<span class="token punctuation">.</span><span class="token function">DisplayAlertAsync</span><span class="token punctuation">(</span><span class="token string">"Error"</span><span class="token punctuation">,</span> $<span class="token string">"Could not save document: {ex.Message}"</span><span class="token punctuation">,</span> <span class="token string">"OK"</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>RelayCommand<span class="token punctuation">]</span>
    <span class="token keyword">private</span> <span class="token keyword">async</span> Task <span class="token function">ShareTextAsync</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>HasText<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>Application<span class="token punctuation">.</span>Current<span class="token operator">?</span><span class="token punctuation">.</span>Windows<span class="token punctuation">.</span><span class="token function">FirstOrDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">.</span>Page <span class="token keyword">is</span> Page page<span class="token punctuation">)</span>
            <span class="token punctuation">{</span>
                <span class="token keyword">await</span> page<span class="token punctuation">.</span><span class="token function">DisplayAlertAsync</span><span class="token punctuation">(</span><span class="token string">"Share"</span><span class="token punctuation">,</span> <span class="token string">"There is no text to share."</span><span class="token punctuation">,</span> <span class="token string">"OK"</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 punctuation">}</span>

        <span class="token keyword">await</span> Share<span class="token punctuation">.</span>Default<span class="token punctuation">.</span><span class="token function">RequestAsync</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ShareTextRequest</span>
        <span class="token punctuation">{</span>
            Text <span class="token operator">=</span> EditorText<span class="token punctuation">,</span>
            Title <span class="token operator">=</span> <span class="token string">"Share Voice Note"</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token preprocessor property">#<span class="token directive keyword">endregion</span></span>

    <span class="token preprocessor property">#<span class="token directive keyword">region</span> Helper Methods</span>

    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">UpdateStatus</span><span class="token punctuation">(</span><span class="token keyword">string</span> text<span class="token punctuation">,</span> <span class="token keyword">string</span><span class="token operator">?</span> colorHex<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        StatusText <span class="token operator">=</span> text<span class="token punctuation">;</span>
        StatusColor <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>colorHex<span class="token punctuation">)</span> <span class="token operator">?</span> Colors<span class="token punctuation">.</span>Gray <span class="token punctuation">:</span> Color<span class="token punctuation">.</span><span class="token function">FromArgb</span><span class="token punctuation">(</span>colorHex<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">UpdateButtonState</span><span class="token punctuation">(</span>Telerik<span class="token punctuation">.</span>Maui<span class="token punctuation">.</span>SpeechRecognizer<span class="token punctuation">.</span>SpeechRecognizerState state<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">switch</span> <span class="token punctuation">(</span>state<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">case</span> Telerik<span class="token punctuation">.</span>Maui<span class="token punctuation">.</span>SpeechRecognizer<span class="token punctuation">.</span>SpeechRecognizerState<span class="token punctuation">.</span>Listening<span class="token punctuation">:</span>
                <span class="token function">UpdateStatus</span><span class="token punctuation">(</span><span class="token string">"Listening..."</span><span class="token punctuation">,</span> <span class="token string">"#2563EB"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">break</span><span class="token punctuation">;</span>
            <span class="token keyword">case</span> Telerik<span class="token punctuation">.</span>Maui<span class="token punctuation">.</span>SpeechRecognizer<span class="token punctuation">.</span>SpeechRecognizerState<span class="token punctuation">.</span>Initializing<span class="token punctuation">:</span>
                <span class="token function">UpdateStatus</span><span class="token punctuation">(</span><span class="token string">"Initializing..."</span><span class="token punctuation">,</span> <span class="token string">"#F59E0B"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">break</span><span class="token punctuation">;</span>
            <span class="token keyword">default</span><span class="token punctuation">:</span>
                <span class="token function">UpdateStatus</span><span class="token punctuation">(</span><span class="token string">"Ready"</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">break</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token preprocessor property">#<span class="token directive keyword">endregion</span></span>
<span class="token punctuation">}</span>
</code></pre><p>The above code results in the following application when executed:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/showing-a-note-taking-app-interface-being-used-through-a-keyboard.gif?sfvrsn=1143ca0e_2" alt="Showing a note-taking app interface being used through a keyboard" /></p><p>In the previous image, you can see the application, which only allows taking notes via the keyboard, which can be tedious, slow and boring. Therefore, we will use the speech-to-text control to improve quick note-taking.</p><h2 id="integrating-the-speechtotextbutton-control-into-the-application">Integrating the SpeechToTextButton Control into the Application</h2><p>The first thing you need to do to use the speech-to-text control is to follow the <a target="_blank" href="https://www.telerik.com/maui-ui/documentation/get-started/first-steps-vs">Telerik .NET MAUI controls installation guide</a>. Once you have done that, add the following namespace in the <code>ContentPage</code> where you want to use the control:</p><pre class=" language-xml"><code class="prism  language-xml">xmlns:telerik="http://schemas.telerik.com/2022/xaml/maui"</code></pre><p>Next, add the control using the <code>RadSpeechToTextButton</code> tag where you want to place it; in our example, it will be located where the <strong>Editor Toolbar</strong> comment is:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadSpeechToTextButton</span>
    <span class="token attr-name"><span class="token namespace">x:</span>Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>SpeechButton<span class="token punctuation">"</span></span>
    <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>3<span class="token punctuation">"</span></span>
    <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
</code></pre><p>Since we will be using the microphone in the app for obtaining the transcription, you need to grant the <a target="_blank" href="https://www.telerik.com/maui-ui/documentation/controls/speechtotextbutton/getting-started#required-permissions">required permissions according to the platform</a> to allow audio recording and voice recognition. For example, for Android, you need to add the following line to <code>AndroidManifest.xml</code>:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;uses-permission android:name="android.permission.RECORD_AUDIO" /&gt;</code></pre><p>The integration of the control provides a button with the necessary functionality to start the speech-to-text process:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/showing-the-button-that-enables-the-speech-to-text-functionality.gif?sfvrsn=8d2c43db_2" alt="Showing the button that enables the speech-to-text functionality, with the microphone activating automatically" /></p><p>In the image above, you can see that when the button to start recording is pressed, the microphone is automatically activated in the status bar (if it&rsquo;s the first execution, it will likely ask for microphone access), indicating that a recording process has started.</p><p>Now we need to handle the events or commands to obtain the transcription, which we will see next.</p><h2 id="available-events-and-commands-in-the-speech-to-text-control-for-.net-maui">Available Events and Commands in the Speech to Text Control for .NET MAUI</h2><p>The speech to text control has events and commands that we can use to react to different situations. For the events, we have the following available:</p><ul><li><code>SpeechRecognized</code>: This occurs when there is a successful speech recognition and includes an argument <code>SpeechRecognizerSpeechRecognizedEventArgs</code>, which contains the <code>FullText</code> obtained from the recognition and <code>FullTextConfidenceScore</code> indicating the confidence level of the recognition.</li><li><code>ErrorOccurred</code>: This occurs when there is an error in the recognition process, includes the argument <code>SpeechRecognizerErrorOccurredEventArgs</code>, which contains the <code>Message</code> property with the error message, the <code>Exception</code> associated with the error and <code>Handled</code> to determine if the error has been handled.</li><li><code>StateChanged</code>: This is fired as soon as there is a change in the state of the speech recognizer.</li></ul><p>On the other hand, we also have some commands that will allow us to handle events directly from the viewmodel if we need to, as is the case for us. To achieve this, we can modify the label of the <code>RadSpeechToTextButton</code> control by adding the commands <code>SpeechRecognizedCommand</code> and <code>ErrorOccurredCommand</code> as shown in the following example:</p><pre class=" language-xml"><code class="prism  language-xml"> <span class="token comment">&lt;!--  Editor Toolbar  --&gt;</span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Border...</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span> <span class="token attr-name">ColumnDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*, Auto, Auto, Auto<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        ...
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadSpeechToTextButton</span>
            <span class="token attr-name"><span class="token namespace">x:</span>Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>SpeechButton<span class="token punctuation">"</span></span>
            <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>3<span class="token punctuation">"</span></span>
            <span class="token attr-name">ErrorOccurredCommand</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding ErrorOccurredCommand}<span class="token punctuation">"</span></span>
            <span class="token attr-name">SpeechRecognizedCommand</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding SpeechRecognizedCommand}<span class="token punctuation">"</span></span>
            <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Grid</span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Border</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Next, we need to handle the commands from the viewmodel as seen below:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token preprocessor property">#<span class="token directive keyword">region</span> Speech Recognition Commands</span>

<span class="token punctuation">[</span>RelayCommand<span class="token punctuation">]</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">SpeechRecognized</span><span class="token punctuation">(</span>SpeechToTextButtonSpeechRecognizedCommandContext context<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    EditorText <span class="token operator">=</span> context<span class="token punctuation">.</span>FullText<span class="token punctuation">;</span>
    <span class="token function">UpdateStatus</span><span class="token punctuation">(</span><span class="token string">"Speech recognized"</span><span class="token punctuation">,</span> <span class="token string">"#10B981"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token punctuation">[</span>RelayCommand<span class="token punctuation">]</span>
<span class="token keyword">private</span> <span class="token keyword">async</span> Task <span class="token function">ErrorOccurredAsync</span><span class="token punctuation">(</span>SpeechToTextButtonErrorOccurredCommandContext context<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token function">UpdateStatus</span><span class="token punctuation">(</span><span class="token string">"Error occurred"</span><span class="token punctuation">,</span> <span class="token string">"#EF4444"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>Application<span class="token punctuation">.</span>Current<span class="token operator">?</span><span class="token punctuation">.</span>Windows<span class="token punctuation">.</span><span class="token function">FirstOrDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">.</span>Page <span class="token keyword">is</span> Page page<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">await</span> page<span class="token punctuation">.</span><span class="token function">DisplayAlertAsync</span><span class="token punctuation">(</span><span class="token string">"Voice Input Error"</span><span class="token punctuation">,</span>
            $<span class="token string">"Unable to process voice input: {context.Message}"</span><span class="token punctuation">,</span>
            <span class="token string">"OK"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token preprocessor property">#<span class="token directive keyword">endregion</span></span>
</code></pre><p>In the previous code, you can see that the commands receive contexts similar to the arguments of the events. The first, <code>SpeechToTextButtonSpeechRecognizedCommandContext</code>, allows obtaining the <code>FullText</code> and <code>FullTextConfidenceScore</code> when there is speech recognition. The second, <code>SpeechToTextButtonErrorOccurredCommandContext</code>, contains the <code>Message</code> and <code>Exception</code> properties when there is an error in the speech recognition.</p><p>You can also see how <code>FullText</code> is assigned to the <code>EditorText</code> property, which is bound to the control of type <code>Editor</code>. This allows the transcription obtained to be displayed in the graphical interface, resulting in the following execution:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/live-demonstration-of-telerik-speech-to-text-control-for-maui.gif?sfvrsn=a3fc5485_2" alt="Live demonstration of Telerik’s Speech-to-Text control for .NET MAUI, enabling real-time voice transcription" /></p><p>Now we can obtain the transcription; however, there is a need for visual indicators that allow users to know what is happening in the application, and we can solve this through the states of the control. Let&rsquo;s see how.</p><h2 id="states-of-the-speech-to-text-control">States of the Speech-to-Text Control</h2><p>One thing that is appreciated as a developer is that Progress Telerik documentation is very clear regarding the architecture and lifecycle of the .NET MAUI SpeechToTextButton control, as can be seen in the following image:</p><p><img src="https://www.telerik.com/maui-ui/documentation/assets/0b2b21d54845c1079dac37312faab870/speechtotext-architecture.png" alt="Architecture and lifecycle of the SpeechToTextButton control" /></p><p>The diagram above shows us a series of states that we can detect thanks to the <code>StateChanged</code> event as seen below:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadSpeechToTextButton</span>
    <span class="token attr-name"><span class="token namespace">x:</span>Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>SpeechButton<span class="token punctuation">"</span></span>
    <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>3<span class="token punctuation">"</span></span>
    <span class="token attr-name">ErrorOccurredCommand</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding ErrorOccurredCommand}<span class="token punctuation">"</span></span>
    <span class="token attr-name">SpeechRecognizedCommand</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding SpeechRecognizedCommand}<span class="token punctuation">"</span></span>
    <span class="token attr-name">StateChanged</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>OnStateChanged<span class="token punctuation">"</span></span>
    <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
</code></pre><p>In the code behind, we can invoke a method from the viewmodel that allows us to determine what to do with the detected state:</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">OnStateChanged</span><span class="token punctuation">(</span><span class="token keyword">object</span> sender<span class="token punctuation">,</span> EventArgs e<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>sender <span class="token keyword">is</span> RadSpeechToTextButton button<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        MainThread<span class="token punctuation">.</span><span class="token function">BeginInvokeOnMainThread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span>
        <span class="token punctuation">{</span>
            _viewModel<span class="token punctuation">.</span><span class="token function">UpdateButtonState</span><span class="token punctuation">(</span>button<span class="token punctuation">.</span>State<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>Within the viewmodel, we will compare the desired state using any of the states defined in the <code>Telerik.Maui.SpeechRecognizer.SpeechRecognizerState</code> enumeration.</p><p>For example, to react to state changes <code>Listening</code> and <code>Initializing</code>, the code would be as follows:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">UpdateButtonState</span><span class="token punctuation">(</span>Telerik<span class="token punctuation">.</span>Maui<span class="token punctuation">.</span>SpeechRecognizer<span class="token punctuation">.</span>SpeechRecognizerState state<span class="token punctuation">)</span>
<span class="token punctuation">{</span>        
    <span class="token keyword">switch</span> <span class="token punctuation">(</span>state<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>            
        <span class="token keyword">case</span> Telerik<span class="token punctuation">.</span>Maui<span class="token punctuation">.</span>SpeechRecognizer<span class="token punctuation">.</span>SpeechRecognizerState<span class="token punctuation">.</span>Listening<span class="token punctuation">:</span>
            <span class="token function">UpdateStatus</span><span class="token punctuation">(</span><span class="token string">"Listening..."</span><span class="token punctuation">,</span> <span class="token string">"#2563EB"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span>
        <span class="token keyword">case</span> Telerik<span class="token punctuation">.</span>Maui<span class="token punctuation">.</span>SpeechRecognizer<span class="token punctuation">.</span>SpeechRecognizerState<span class="token punctuation">.</span>Initializing<span class="token punctuation">:</span>
            <span class="token function">UpdateStatus</span><span class="token punctuation">(</span><span class="token string">"Initializing..."</span><span class="token punctuation">,</span> <span class="token string">"#F59E0B"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span>
        <span class="token keyword">default</span><span class="token punctuation">:</span>
            <span class="token function">UpdateStatus</span><span class="token punctuation">(</span><span class="token string">"Ready"</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Finally, in the graphical interface code, we can add visual indicators that provide feedback to the user about the state of the control. In our example, we do this in the comment section <strong>Status Bar</strong>:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token comment">&lt;!--  Status Bar  --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Border</span>
    <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
    <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>16,12<span class="token punctuation">"</span></span>
    <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#F3F4F6<span class="token punctuation">"</span></span>
    <span class="token attr-name">StrokeShape</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>RoundRectangle 12<span class="token punctuation">"</span></span>
    <span class="token attr-name">StrokeThickness</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span> <span class="token attr-name">ColumnDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Auto, *, Auto<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Ellipse</span>
            <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding StatusColor}<span class="token punctuation">"</span></span>
            <span class="token attr-name">HeightRequest</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">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span>
            <span class="token attr-name">WidthRequest</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 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">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
            <span class="token attr-name">Margin</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>12,0,0,0<span class="token punctuation">"</span></span>
            <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>14<span class="token punctuation">"</span></span>
            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding StatusText}<span class="token punctuation">"</span></span>
            <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#374151<span class="token punctuation">"</span></span>
            <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Label</span>
            <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span>
            <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>12<span class="token punctuation">"</span></span>
            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding CharacterCount}<span class="token punctuation">"</span></span>
            <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#9CA3AF<span class="token punctuation">"</span></span>
            <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Grid</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Border</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Once the previous code has been replaced, we will graphically see the state changes, to indicate to users that the component is ready to start transcription, if it is listening to speech or if speech has been recognized correctly:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/handling-the-state-validation-of-the-speech-to-text-control.gif?sfvrsn=4bfd00e8_2" alt="Handling the state validation of the Speech-to-Text control, providing user feedback about what is happening in the application" /></p><p>In the above image, you can see the state changes in action, according to the actions performed by the user on the speech to text control.</p><h2 id="conclusion">Conclusion</h2><p>Throughout this article, you have been able to learn about the SpeechToTextButton control from Telerik for .NET MAUI applications.</p><p>Implementing this type of component in your mobile applications can greatly simplify the friction that exists with users when it comes to entering lengthy or rapid text, something very trendy today with AI-based apps. I encourage you to try it out and help your users get the most out of your applications.</p><p>If you aren&rsquo;t already using Telerik UI for .NET MAUI, it comes with a free 30-day trial:</p><p><a target="_blank" href="https://www.telerik.com/try/ui-for-maui" class="Btn">Try Now</a></p>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:446ac613-ef0e-477a-ba38-7280c81f24f0</id>
    <title type="text">New in ThemeBuilder: Typography and AI Theming Enhancements</title>
    <summary type="text">See how the ThemeBuilder Typography module for centralized font management and component-level AI theming enhancements can help in our app design and development.</summary>
    <published>2026-04-01T19:45:40Z</published>
    <updated>2026-04-06T02:18:19Z</updated>
    <author>
      <name>Hassan Djirdeh </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/new-themebuilder-typography-ai-theming-enhancements"/>
    <content type="text"><![CDATA[<p><span class="featured">See how the ThemeBuilder Typography module for centralized font management and component-level AI theming enhancements can help in our app design and development.</span></p><p><a target="_blank" href="https://www.telerik.com/themebuilder">Progress ThemeBuilder</a> is a visual styling tool for customizing Telerik and Kendo UI components. Instead of digging through component documentation, ThemeBuilder provides an intuitive interface that allows us to see styling changes applied in real time. We can adjust colors, spacing, typography and more, then export production-ready CSS/SASS for our applications.</p><p>With the <a target="_blank" href="https://www.telerik.com/support/whats-new/themebuilder#what_s-new-2025-q4">2025 Q4 release</a>, ThemeBuilder introduced two cool updates: a dedicated Typography module for centralized font management and component-level AI theming enhancements that give us finer control over AI-generated styles. In this article, we&rsquo;ll spend a little time exploring both.</p><h2 id="setting-up-a-theme-with-ai">Setting Up a Theme with AI</h2><p>Before jumping into the new features, let&rsquo;s quickly set up a theme using AI to see how these enhancements fit into the workflow. In the ThemeBuilder interface, we&rsquo;ll find a <strong>Generate</strong> panel where we can describe our desired theme in plain English. To get started, we can enter something like: <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></p><p>After generating, the AI analyzes the description and produces a cohesive design system. Within seconds, we&rsquo;ll see a complete theme applied across all components: buttons adopt a refined blue accent, inputs feature subtle borders with appropriate focus states, and data visualization components like charts and grids receive complementary styling that maintains readability.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/theme-builder-modern-analytics-theme.png?sfvrsn=602edf2a_2" alt="" /></p><p>This theme serves as a good starting point. The colors work well together, the spacing feels balanced and there&rsquo;s visual consistency across the component library.</p><p>But what if we want to adjust the appearance of specific components without altering the entire theme? This is where the new component-level AI theming comes in.</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">Workflows in the Age of AI: How Design &amp; Development Workflows Changed in 2025&mdash;and What Comes Next</h4></div><div class="col-8"><p class="u-fs16 u-mb0"><a target="_blank" href="https://www.telerik.com/ai-design-development-workflows-report-2025">Check out our designer-developer survey report.</a> It&rsquo;s a look back at how AI reshaped collaboration in 2025&mdash;and what it means for teams, tools and roadmaps in 2026.</p></div></div><hr class="u-mb3" /></aside><h2 id="component-level-ai-theming">Component-Level AI Theming</h2><p>One of the challenges with theme generation with AI has been the &ldquo;all or nothing&rdquo; approach. Previous AI theming would regenerate our entire theme, which was great for starting fresh, but less helpful when we only wanted to tweak how buttons looked or adjust the styling of our data grid headers.</p><p>The new component-level AI theming enhancements solve this problem. We can now target individual components with AI-assisted styling while preserving our overall theme. Instead of manually hunting through variables and properties, we can use the AI theming interface to target just, say, the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/buttons/button">React Button</a> component.</p><p>To see an example of this, we can enter a specific prompt like: <em>&ldquo;Make the primary button more prominent with a stronger visual presence and subtle gradient that draws attention for call-to-action scenarios.&rdquo;</em></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/theme-builder-button-component-override.gif?sfvrsn=2bd5c13c_1" alt="" /></p><p>The AI adjusted only the primary (solid) button-related variables and styles, enhancing the gradient effect and adding a bit more visual weight to the component. The rest of our theme remains untouched!</p><p>We can continue refining our design in the same way. For example, we can apply an AI-driven override to the specific <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/inputs/textbox">React TextBox</a> component to make it more visually distinctive and usable.</p><p>We might use a prompt like: <em>&ldquo;Redesign the TextBox component with a more prominent border, a subtle background tint, stronger focus glow, and slightly increased padding to make input fields visually distinct and easier to scan in complex layouts.&rdquo;</em></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/theme-builder-textbox-component-override.gif?sfvrsn=b7542dec_1" alt="" /></p><p>The AI updates only the TextBox-related styles while preserving other existing styles in the components module.</p><h2 id="new-typography-module">New Typography Module</h2><p>While AI theming handles creative decisions, the new Typography module provides structured, systematic control over typography settings of our theme and is located alongside the existing modules like Metrics, Colors, etc.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/theme-builder-typography.png?sfvrsn=e301ae26_2" alt="" /></p><p>In the module, we can define reusable typography variables that bundle multiple text properties into a single unit. Each variable can include font family, size, line height, letter spacing, text transform, font style and text decoration.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/theme-builder-typography-dialog.png?sfvrsn=abccd50f_2" alt="" /></p><p>Once defined, these typography variables can be assigned to component parts like inputs, headers and form labels. Here&rsquo;s an example of applying a custom typography set to the text of the Button component.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/theme-builder-applying-custom-typography.png?sfvrsn=f209de05_2" alt="" /></p><p>This provides both flexibility and long-term maintainability, allowing typography variables to be defined once and applied consistently across components with just a few clicks.</p><h2 id="wrap-up">Wrap-up</h2><p>The 2025 Q4 updates to ThemeBuilder address two common pain points.</p><ul><li>Component-level AI theming lets us refine specific parts of our theme without starting over, making AI generation more practical for real-world projects.</li><li>The Typography module brings font management into a centralized, reusable system, letting us define text styles once and apply them consistently across components with ease.</li></ul><p>Ready to try these new capabilities? Explore <a target="_blank" href="https://www.telerik.com/themebuilder">ThemeBuilder</a> and see how the latest updates can streamline your theming workflow.</p><p>If you aren&rsquo;t already using Telerik or Kendo UI components, see how ThemeBuilder complements these robust libraries in the <a target="_blank" href="https://www.telerik.com/devcraft">Telerik DevCraft bundles</a>.</p><p><a target="_blank" href="https://www.telerik.com/try/devcraft-ultimate" class="Btn">Try Telerik DevCraft</a></p>]]></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-06T02:18:19Z</updated>
    <author>
      <name>Dany Paredes </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/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>]]></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-06T02:18:19Z</updated>
    <author>
      <name>Peter Vogel </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/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>]]></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-06T02:18:19Z</updated>
    <author>
      <name>Héctor Pérez </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/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>]]></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-06T02:18:19Z</updated>
    <author>
      <name>Hassan Djirdeh </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/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>]]></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-06T02:18:19Z</updated>
    <author>
      <name>Dhananjay Kumar </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/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>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:11b6a5e4-ce35-4e16-b40f-cab882975edb</id>
    <title type="text">AI Crash Course: Prompt Engineering</title>
    <summary type="text">Because AI models are non-deterministic by nature, even the most perfect, precise prompt cannot prevent the occasional hallucination or error. However, prompt engineering is one of our most effective and accessible tools for getting a model to behave in the way we would like.</summary>
    <published>2026-03-26T19:44:35Z</published>
    <updated>2026-04-06T02:18:19Z</updated>
    <author>
      <name>Kathryn Grayson Nanz </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/ai-crash-course-prompt-engineering"/>
    <content type="text"><![CDATA[<p><span class="featured">AI models function more like they&rsquo;re completing a transcript than holding a conversation. Providing plenty of context in our prompts helps them output the results we&rsquo;re actually looking for.</span></p><p>Prompting is the primary way we provide input to AI models. When we need a model to generate something for us, we begin the process by prompting it with a plain-language request to complete the task. When we&rsquo;re having simple, back-and-forth personal exchanges with conversational models, our prompts can be extremely casual&mdash;sometimes even identical to the way we&rsquo;d talk to another human being! </p><p>However, when we&rsquo;re considering generative AI in the context of a feature we&rsquo;re adding to our applications, casual prompts will no longer suffice.&nbsp;<span style="background-color:transparent;color:inherit;font-family:inherit;font-size:inherit;text-align:inherit;text-transform:inherit;word-spacing:normal;caret-color:auto;white-space:inherit;">To leverage AI in production applications, the results need to be 1) relatively consistent and 2) formatted in an expected, parseable structure. If a user asks the same question twice, the output should be similar both times. If our frontend was built to map over a JSON object, we don&rsquo;t want the model to output markdown.</span></p><p>Because AI models are non-deterministic by nature, even the most perfect, precise prompt cannot prevent the occasional hallucination or error. However, prompt engineering is one of our most effective and accessible tools for getting a model to behave in the way we would like. </p><h2 id="why-engineer-prompts-">Why Engineer Prompts?</h2><p>In the 2020 paper <a target="_blank" href="https://arxiv.org/pdf/2005.14165">Language Models are Few-Shot Learners</a>, Brown, et al. demonstrate that GPT-3 is able to successfully leverage in-prompt demonstrations (or &ldquo;shots&rdquo;) to perform tasks it was not explicitly trained to complete. </p><p>This approach is known as &ldquo;in-context learning.&rdquo; The team tested the model with &ldquo;zero-shot&rdquo; (only the instruction), &ldquo;one-shot&rdquo; (one demonstration) and &ldquo;few-shot&rdquo; prompts (in the case of this study, 10-100 demonstrations, depending on available context&mdash;but worth noting that the term &ldquo;few-shot&rdquo; prompting today generally only refers to the inclusion of 2-10 demonstrations). </p><p>As we can see in the chart below, they prove that, &ldquo;While zero-shot performance improves steadily with model size, few-shot performance increases more rapidly, demonstrating that larger models are more proficient at in-context learning.&rdquo; </p><p><img sf-image-responsive="true" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/.net-maui-aiprompt/chart.png?sfvrsn=2fb2eb4b_2" height="288" style="max-width:100%;height:auto;" title="Aggregate Performance Across Benchmarks" width="460" alt="A line chart showing the differences in accuracy between zero shot, one shot, and few shot prompting. " sf-size="143582" /></p><p>The important takeaway from this study for us is that, by using this approach, they were able to achieve results with non-finetuned models that were on par or exceeding the results from finetuned models. </p><p>Models have, of course, advanced since the writing of this paper&mdash;it&rsquo;s no longer entirely accurate to say that prompt engineering alone will offer equivalent results to finetuning (or other newer techniques, like RAG). However, it <em>is</em> still fair to say that if we engineer our prompts, we will achieve noticeably high-quality results. Depending on our project goal and budget, that may be good enough.</p><h2 id="the-structure-of-a-well-engineered-prompt">The Structure of a Well-Engineered Prompt</h2><p>As of the time of this writing, there&rsquo;s a common structure that has emerged as a best practice approach for prompt engineering: <strong>role + task + format + example</strong>. </p><p>Prompts that include at least one of each of these pieces tend to perform better than prompts that do not&mdash;although there has been some documented difference between the models as to which order is preferable. For example, one model might do better when the task is the first thing listed, another when the task is last. Experimenting with your model of choice to see what gets the best results is still a required aspect of the prompt engineering process.</p><p>If you&rsquo;re totally new to prompt engineering and would like a deeper dive into that structural method, you might enjoy <a target="_blank" href="https://www.telerik.com/blogs/understanding-architecture-prompt">Understanding the Architecture of a Prompt</a>, which explains in greater detail how to most effectively write each part. </p><p>To look at a sample prompt using this structure, this is the system prompt from a playlist generating app I built with my fellow Progress DevRel (and friend) Alyssa Nicoll: </p><blockquote><code>const SYSTEM_PROMPT =</code>You are a music recommendation assistant.
    Given a user's prompt (mood, activity, genre, era, etc.), return a JSON object with a "tracks" array that includes at least 10 tracks.
    Each track must have: title (string), artist (string), album (string), release year (number), confidence ranking for how well this song fits the prompt (number 0-100), one sentence explaining why this song fits the prompt (string). Return an error for unusable prompts: offensive content, gibberish, or explicitly impossible requests. Otherwise always try to generate recommendations. Return ONLY valid JSON, no markdown or explanation.
    Example success: {"tracks":[{"title":"Song Name","artist":"Artist Name","album":"Album Name","year":2020,"confidence":92,"reason":"The driving rhythm and anthemic chorus perfectly match the high-energy workout vibe."}]}``;</blockquote><p>As we do in that example, you may also find it helpful to think about the &ldquo;system prompt&rdquo; and the &ldquo;user prompt&rdquo; separately. In fact, many model APIs offer these as distinct inputs. The system prompt is intended to specify the context and description for the task, while the user prompt contains the task itself. </p><p>In the playlist generator example, you&rsquo;ll note that the end user&rsquo;s input (the actual genre, mood, etc. that the model is meant to generate the playlist around) is not included. In this case, the system and user prompts get passed in via the OpenAI API under separate system and user <code>roles</code>. </p><pre><code class="lang-jsx">const completion = await openai.chat.completions.create({
<span class="hljs-symbol">      model:</span> <span class="hljs-string">"gpt-4o-mini"</span>,
<span class="hljs-symbol">      messages:</span> [
        { <span class="hljs-string">role:</span> <span class="hljs-string">"system"</span>, <span class="hljs-string">content:</span> SYSTEM_PROMPT },
        { <span class="hljs-string">role:</span> <span class="hljs-string">"user"</span>, <span class="hljs-string">content:</span> prompt.trim() },
      ],
<span class="hljs-symbol">      temperature:</span> <span class="hljs-number">0.7</span>,
    });
</code></pre><h2 id="why-does-prompt-engineering-work-">Why Does Prompt Engineering Work?</h2><p>While it&rsquo;s helpful to know best practices, as developers it often serves us better to know the &ldquo;why&rdquo; behind the methodology. In this case, why does a prompt that&rsquo;s engineered like the one above perform better than a prompt that just says, &ldquo;Recommend 10 songs based on the user&rsquo;s input and format it as a JSON object&rdquo;? </p><p>Mostly, it has to do with how models work at a high level. Prompts tend to be more successful when they mirror the types of data that the model was trained on. </p><p>For now, what&rsquo;s most important to remember is that AI models are&mdash;at their core&mdash;document completion machines. Early AI models (before the chat interface became popular) didn&rsquo;t &ldquo;respond&rdquo; to a prompt, they just continued them. So if my prompt was &ldquo;Mary had a little,&rdquo; the LLM would likely return &ldquo;lamb&rdquo; to complete the line. If you haven&rsquo;t read the <a target="_blank" href="https://www.telerik.com/blogs/ai-crash-course-tokens-prediction-temperature">Tokens, Predictions and Temperature</a> article from earlier in this series, I&rsquo;d encourage you to go give it a quick skim&mdash;it explains that prediction process in more detail. </p><p>Even the chat models we&rsquo;re so familiar with today are still doing exactly this. They&rsquo;ve just been trained on transcripts of conversations, so they can &ldquo;understand&rdquo; the patterns of a back-and-forth exchange. When we interact with a conversational AI (like ChatGPT or Claude), the API is just wrapping our inputs (and its own outputs) in the structure of a transcript, so that the LLM can process them together in a structured context&mdash;like a document. This allows it to leverage its prediction mechanisms in order to &ldquo;complete&rdquo; that document. To the user, it feels like having a real conversation. To the LLM, it&rsquo;s more like we submitted a half-finished play script and asked it to generate the rest for us. </p><p>There is, admittedly, very little functional difference between thinking that a model is conversing with us vs. understanding that it&rsquo;s completing our conversational transcript. However, making that mental shift can help us shape our prompts more effectively. </p><p>Often, when we think about NLP, we assume it means that because a computer can understand our &ldquo;natural&rdquo; language, we can instruct it in the same way we would another human. While it&rsquo;s true that we can use natural language&mdash;as in words and sentences instead of code&mdash;the LLM is not going to process our request like a human would. Instead, it&rsquo;s going to insert our prompt as the most recent line in its script, and attempt to continue the script to the best of its ability, based on all the other sample scripts it was trained on. </p><p>By phrasing our requests like the samples in the training data and giving it as much context as possible directly in the prompt, we can enable it to make better, more accurate completions.</p><hr /><p><strong>Stay tuned:</strong> Join us in the ever-evolving <a href="https://www.telerik.com/blogs/artificial-intelligence" target="_blank">conversation about AI</a>.</p>]]></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-06T02:18:19Z</updated>
    <author>
      <name>Jon Hilton </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/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>]]></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-06T02:18:19Z</updated>
    <author>
      <name>Alyssa Nicoll </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/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>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:81ae8790-39c7-475d-9a30-6d8910a1d815</id>
    <title type="text">Getting Started with the BottomSheet Component for .NET MAUI</title>
    <summary type="text">If your mobile app needs a slide-up section to appear from the bottom of the screen, check out the .NET MAUI BottomSheet component.</summary>
    <published>2026-03-23T21:49:40Z</published>
    <updated>2026-04-06T02:18:19Z</updated>
    <author>
      <name>Héctor Pérez </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/getting-started-bottomsheet-component-net-maui"/>
    <content type="text"><![CDATA[<p><span class="featured">If your mobile app needs a slide-up section to appear from the bottom of the screen, check out the .NET MAUI BottomSheet component.</span></p><p>In some modern mobile applications, we can see a component called Bottom Sheet in action, which allows the user to slide a section up from the bottom of the application to display actions or information without changing the screen.</p><p>This type of component does not exist as part of the native .NET MAUI controls. Fortunately, the Progress Telerik suite of controls for .NET MAUI offers the <a target="_blank" href="https://www.telerik.com/maui-ui/bottomsheet">.NET MAUI BottomSheet</a> component, which we will analyze during this post. Let&rsquo;s get started!</p><h2 id="discovering-the-telerik-.net-maui-bottomsheet-component-for-.net-maui">Discovering the Telerik .NET MAUI BottomSheet Component for .NET MAUI</h2><p>We will explore different features of the Bottom Sheet component, for which I will show you a window created with XAML code that could well represent a section of a real application. Next, I will show you how to implement the Bottom Sheet control to display selection options to users in the same window.</p><h2 id="creating-an-example-project">Creating an Example Project</h2><p>Suppose we have a project that allows users to order food from restaurants through an application. For the creation of the XAML page, I have used different controls from the Telerik UI for .NET MAUI suite, which enable the quick creation of custom graphical interfaces:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid.RowDefinitions</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>RowDefinition</span> <span class="token attr-name">Height</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>.2*<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>RowDefinition</span> <span class="token attr-name">Height</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>.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>Grid.RowDefinitions</span><span class="token punctuation">&gt;</span></span>

    <span class="token comment">&lt;!--  Header Section  --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>VerticalStackLayout</span> <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>25,25,25,0<span class="token punctuation">"</span></span> <span class="token attr-name">Spacing</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 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">FontAttributes</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">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>12<span class="token punctuation">"</span></span>
            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>DELIVERY ADDRESS<span class="token punctuation">"</span></span>
            <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Grid</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid.ColumnDefinitions</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ColumnDefinition</span> <span class="token attr-name">Width</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ColumnDefinition</span> <span class="token attr-name">Width</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Auto<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid.ColumnDefinitions</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid.GestureRecognizers</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TapGestureRecognizer</span> <span class="token attr-name">Tapped</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>OnAddressTapped<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid.GestureRecognizers</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"><span class="token namespace">x:</span>Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>CurrentAddressLabel<span class="token punctuation">"</span></span>
                <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>16<span class="token punctuation">"</span></span>
                <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>123 Main Street, City<span class="token punctuation">"</span></span>
                <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>White<span class="token punctuation">"</span></span>
                <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Label</span>
                <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
                <span class="token attr-name">Margin</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>10,0,0,0<span class="token punctuation">"</span></span>
                <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>14<span class="token punctuation">"</span></span>
                <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>▼<span class="token punctuation">"</span></span>
                <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>White<span class="token punctuation">"</span></span>
                <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Grid</span><span class="token punctuation">&gt;</span></span>

        <span class="token comment">&lt;!--  Search Bar  --&gt;</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadBorder</span>
            <span class="token attr-name">Padding</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">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#6B5BAF<span class="token punctuation">"</span></span>
            <span class="token attr-name">CornerRadius</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 punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span> <span class="token attr-name">ColumnDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Auto,*<span class="token punctuation">"</span></span><span class="token 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">Margin</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0,0,10,0<span class="token punctuation">"</span></span>
                    <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>16<span class="token punctuation">"</span></span>
                    <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span>
                    <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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><span class="token namespace">telerik:</span>RadEntry</span>
                    <span class="token attr-name"><span class="token namespace">x:</span>Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>StoreSearchEntry<span class="token punctuation">"</span></span>
                    <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
                    <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Transparent<span class="token punctuation">"</span></span>
                    <span class="token attr-name">BorderThickness</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span>
                    <span class="token attr-name">ClearButtonVisibility</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>WhileEditing<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>Search a restaurant or dish<span class="token punctuation">"</span></span>
                    <span class="token attr-name">PlaceholderColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#B8B0D0<span class="token punctuation">"</span></span>
                    <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Grid</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">telerik:</span>RadBorder</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>VerticalStackLayout</span><span class="token punctuation">&gt;</span></span>

    <span class="token comment">&lt;!--  Store List  --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadBorder</span>
        <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
        <span class="token attr-name">Margin</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0,10,0,0<span class="token punctuation">"</span></span>
        <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#F2F1F6<span class="token punctuation">"</span></span>
        <span class="token attr-name">CornerRadius</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>25,25,0,0<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadCollectionView</span>
            <span class="token attr-name"><span class="token namespace">x:</span>Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>StoresCollection<span class="token punctuation">"</span></span>
            <span class="token attr-name">Margin</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>15<span class="token punctuation">"</span></span>
            <span class="token attr-name">SelectionChanged</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>OnStoreSelected<span class="token punctuation">"</span></span>
            <span class="token attr-name">SelectionMode</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Single<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadCollectionView.ItemsLayout</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>CollectionViewLinearLayout</span> <span class="token attr-name">ItemSpacing</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>15<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">telerik:</span>RadCollectionView.ItemsLayout</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadCollectionView.ItemTemplate</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>DataTemplate</span><span class="token punctuation">&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Border</span>
                        <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span>
                        <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>White<span class="token punctuation">"</span></span>
                        <span class="token attr-name">StrokeShape</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>RoundRectangle 15<span class="token punctuation">"</span></span>
                        <span class="token attr-name">StrokeThickness</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Border.Shadow</span><span class="token punctuation">&gt;</span></span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Shadow</span>
                                <span class="token attr-name">Brush</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#CFD0D4<span class="token punctuation">"</span></span>
                                <span class="token attr-name">Opacity</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0.5<span class="token punctuation">"</span></span>
                                <span class="token attr-name">Radius</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">Offset</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>5,5<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Border.Shadow</span><span class="token punctuation">&gt;</span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span> <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">RowDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>150,Auto<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                            <span class="token comment">&lt;!--  Store Header Image  --&gt;</span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span><span class="token punctuation">&gt;</span></span>
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid.RowDefinitions</span><span class="token punctuation">&gt;</span></span>
                                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>RowDefinition</span> <span class="token attr-name">Height</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>.6*<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>RowDefinition</span> <span class="token attr-name">Height</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>.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>Grid.RowDefinitions</span><span class="token punctuation">&gt;</span></span>
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid.ColumnDefinitions</span><span class="token punctuation">&gt;</span></span>
                                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ColumnDefinition</span> <span class="token attr-name">Width</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>.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>ColumnDefinition</span> <span class="token attr-name">Width</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>.2*<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ColumnDefinition</span> <span class="token attr-name">Width</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>.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>Grid.ColumnDefinitions</span><span class="token punctuation">&gt;</span></span>

                                <span class="token comment">&lt;!--  Header Image  --&gt;</span>
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Image</span>
                                    <span class="token attr-name">Grid.RowSpan</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">Grid.ColumnSpan</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>3<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">Aspect</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>AspectFill<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">Source</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding Header}<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>

                                <span class="token comment">&lt;!--  Logo with gradient border  --&gt;</span>
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span>
                                    <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">Margin</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>10,0,0,0<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">HeightRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>70<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">HorizontalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Start<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>End<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">WidthRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>70<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Border</span>
                                        <span class="token attr-name">HeightRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>65<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">HorizontalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">StrokeShape</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Ellipse<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">StrokeThickness</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>3<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">WidthRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>65<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Border.Stroke</span><span class="token punctuation">&gt;</span></span>
                                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>LinearGradientBrush</span> <span class="token attr-name">EndPoint</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0,1<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GradientStop</span> <span class="token attr-name">Offset</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0.0<span class="token punctuation">"</span></span> <span class="token attr-name">Color</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#FEFEEF<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GradientStop</span> <span class="token attr-name">Offset</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0.25<span class="token punctuation">"</span></span> <span class="token attr-name">Color</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#EBD570<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GradientStop</span> <span class="token attr-name">Offset</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0.5<span class="token punctuation">"</span></span> <span class="token attr-name">Color</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#FF94C3<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GradientStop</span> <span class="token attr-name">Offset</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0.75<span class="token punctuation">"</span></span> <span class="token attr-name">Color</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#A573E4<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GradientStop</span> <span class="token attr-name">Offset</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1.0<span class="token punctuation">"</span></span> <span class="token attr-name">Color</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#A9E2EE<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>LinearGradientBrush</span><span class="token punctuation">&gt;</span></span>
                                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Border.Stroke</span><span class="token punctuation">&gt;</span></span>
                                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Image</span>
                                            <span class="token attr-name">Aspect</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>AspectFill<span class="token punctuation">"</span></span>
                                            <span class="token attr-name">HorizontalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span>
                                            <span class="token attr-name">Source</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding Logo}<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Border</span><span class="token punctuation">&gt;</span></span>
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>

                                <span class="token comment">&lt;!--  Rating Badge  --&gt;</span>
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Border</span>
                                    <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">Margin</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0,0,10,10<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>10,5<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#F8F8F7<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">HeightRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>35<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">HorizontalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">StrokeShape</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>RoundRectangle 10<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">StrokeThickness</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>End<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">WidthRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>70<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>HorizontalStackLayout</span>
                                        <span class="token attr-name">HorizontalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">Spacing</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>8<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Label</span>
                                            <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>14<span class="token punctuation">"</span></span>
                                            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>⭐<span class="token punctuation">"</span></span>
                                            <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Label</span>
                                            <span class="token attr-name">FontAttributes</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">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>14<span class="token punctuation">"</span></span>
                                            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding Rating}<span class="token punctuation">"</span></span>
                                            <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Black<span class="token punctuation">"</span></span>
                                            <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>HorizontalStackLayout</span><span class="token punctuation">&gt;</span></span>
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Border</span><span class="token punctuation">&gt;</span></span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>

                            <span class="token comment">&lt;!--  Store Info  --&gt;</span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>VerticalStackLayout</span>
                                <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
                                <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>15<span class="token punctuation">"</span></span>
                                <span class="token attr-name">Spacing</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Label</span>
                                    <span class="token attr-name">FontAttributes</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">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>18<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding Name}<span class="token punctuation">"</span></span>
                                    <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Grid</span> <span class="token attr-name">ColumnDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*,*,*<span class="token punctuation">"</span></span><span class="token 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">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>13<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding Minimum, StringFormat=<span class="token punctuation">'</span>${0} min<span class="token punctuation">'</span>}<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#666666<span class="token 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">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>13<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">HorizontalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding ServiceFee, StringFormat=<span class="token punctuation">'</span>Fee: ${0}<span class="token punctuation">'</span>}<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#666666<span class="token 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">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>13<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">HorizontalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>End<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding DeliveryTime}<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#666666<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>VerticalStackLayout</span><span class="token punctuation">&gt;</span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Border</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>DataTemplate</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">telerik:</span>RadCollectionView.ItemTemplate</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">telerik:</span>RadCollectionView</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">telerik:</span>RadBorder</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>The result is a beautiful graphical interface that showcases some fictional restaurants, along with additional controls like a search bar and a physical address selector:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/screenshot-of-a-food-ordering-stores-page-built-using-telerik-ui-components-for-net-maui.png?sfvrsn=7724c601_2" alt="Screenshot of a food ordering stores page built using Telerik UI components for .NET MAUI" /></p><p>In the screenshot above, you can see some Telerik components used, such as the following:</p><ul><li><code>RadEntry</code>: For the store search bar</li><li><code>RadBorder</code>: To enhance the appearance of the search bar and list items</li><li><code>RadCollection</code>: To display the list of stores</li></ul><p>At the top of the app, I have placed a fictional address below the text <strong>Delivery Address</strong>. Ideally, users should be able to select a different delivery address if needed without leaving the current screen. This is an excellent use case for a Bottom Sheet.</p><h2 id="getting-to-know-the-telerik-bottomsheet-component">Getting to Know the Telerik BottomSheet Component</h2><p>To implement the Bottom Sheet component, it&rsquo;s essential to understand that it consists of three parts that we can configure:</p><ul><li><strong>BottomSheet Main Content</strong>: Container for the graphic content that will be visible before displaying the Bottom Sheet.</li><li><strong>BottomSheet Content</strong>: Content that fills the Bottom Sheet and that we will show as options or additional information to the user.</li><li><strong>BottomSheet Handle</strong>: A visual cue that indicates to the user that they can drag the Bottom Sheet.</li></ul><p>You can see the location of each of these parts graphically below:</p><p><img src="https://www.telerik.com/maui-ui/documentation/assets/e969b13abd4921187e78b87b013681f9/bottomsheet-visual-structure.png" alt="Visual structure of a Telerik BottomSheet control for .NET MAUI" /></p><p>Now that we have this information, let&rsquo;s proceed to add a Bottom Sheet to the project.</p><h2 id="adding-the-bottomsheet-component-to-a-.net-maui-project">Adding the BottomSheet Component to a .NET MAUI Project</h2><p>Once we are familiar with the main parts of the Bottom Sheet control, the next step is to migrate the existing UI content into the <strong>BottomSheet Main Content</strong> section, using the <code>Content</code> property as follows:</p><pre class=" language-xml"><code class="prism  language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadBottomSheet</span> <span class="token attr-name"><span class="token namespace">x:</span>Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>AddressBottomSheet<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadBottomSheet.Content</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span><span class="token punctuation">&gt;</span></span>
            ...
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>
     <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">telerik:</span>RadBottomSheet.Content</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">telerik:</span>RadBottomSheet</span><span class="token punctuation">&gt;</span></span>

</code></pre><p>The above will determine the content over which the Bottom Sheet will appear. Next, we need to specify the <code>BottomSheetContent</code> tag, where we will define the content that will be shown to the user when the Bottom Sheet appears:</p><pre class=" language-xml"><code class="prism  language-xml">    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadBottomSheet</span> <span class="token attr-name"><span class="token namespace">x:</span>Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>AddressBottomSheet<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        ...
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadBottomSheet.BottomSheetContent</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span>
                <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>20,20,20,60<span class="token punctuation">"</span></span>
                <span class="token attr-name">RowDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Auto,Auto,*,Auto<span class="token punctuation">"</span></span>
                <span class="token attr-name">RowSpacing</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>15<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>

                <span class="token comment">&lt;!--  Header  --&gt;</span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span> <span class="token attr-name">ColumnDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*,Auto<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>VerticalStackLayout</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">FontAttributes</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">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>22<span class="token punctuation">"</span></span>
                            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span> Delivery Address<span class="token punctuation">"</span></span>
                            <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#333333<span class="token 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">Margin</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0,5,0,0<span class="token punctuation">"</span></span>
                            <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>13<span class="token punctuation">"</span></span>
                            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Select or add a new delivery address<span class="token punctuation">"</span></span>
                            <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#888888<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>VerticalStackLayout</span><span class="token punctuation">&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadTemplatedButton</span>
                        <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
                        <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Transparent<span class="token punctuation">"</span></span>
                        <span class="token attr-name">Clicked</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>OnCloseBottomSheet<span class="token punctuation">"</span></span>
                        <span class="token attr-name">Content</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>✕<span class="token punctuation">"</span></span>
                        <span class="token attr-name">CornerRadius</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>20<span class="token punctuation">"</span></span>
                        <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>20<span class="token punctuation">"</span></span>
                        <span class="token attr-name">HeightRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>40<span class="token punctuation">"</span></span>
                        <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#666666<span class="token punctuation">"</span></span>
                        <span class="token attr-name">WidthRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>40<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>

                <span class="token comment">&lt;!--  Search Address  --&gt;</span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadBorder</span>
                    <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
                    <span class="token attr-name">Padding</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>12<span class="token punctuation">"</span></span>
                    <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#EAEAEA<span class="token punctuation">"</span></span>
                    <span class="token attr-name">CornerRadius</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Grid</span> <span class="token attr-name">ColumnDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Auto,*<span class="token punctuation">"</span></span><span class="token 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">Margin</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0,0,10,0<span class="token punctuation">"</span></span>
                            <span class="token attr-name">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>16<span class="token punctuation">"</span></span>
                            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span>
                            <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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><span class="token namespace">telerik:</span>RadEntry</span>
                            <span class="token attr-name"><span class="token namespace">x:</span>Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>AddressSearchEntry<span class="token punctuation">"</span></span>
                            <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
                            <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Transparent<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>Search your addresses...<span class="token punctuation">"</span></span>
                            <span class="token attr-name">PlaceholderColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#999999<span class="token punctuation">"</span></span>
                            <span class="token attr-name">BorderThickness</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span>
                            <span class="token attr-name">ClearButtonVisibility</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>WhileEditing<span class="token punctuation">"</span></span>
                            <span class="token attr-name">TextChanged</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>OnAddressSearchTextChanged<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">telerik:</span>RadBorder</span><span class="token punctuation">&gt;</span></span>

                <span class="token comment">&lt;!--  Address List --&gt;</span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadCollectionView</span>
                    <span class="token attr-name"><span class="token namespace">x:</span>Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>AddressesCollectionView<span class="token punctuation">"</span></span>
                    <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span>
                    <span class="token attr-name">SelectionChanged</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>OnAddressSelectionChanged<span class="token punctuation">"</span></span>
                    <span class="token attr-name">SelectionMode</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Single<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadCollectionView.ItemsLayout</span><span class="token punctuation">&gt;</span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>CollectionViewLinearLayout</span> <span class="token attr-name">ItemSpacing</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 punctuation">/&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">telerik:</span>RadCollectionView.ItemsLayout</span><span class="token punctuation">&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadCollectionView.ItemTemplate</span><span class="token punctuation">&gt;</span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>DataTemplate</span><span class="token punctuation">&gt;</span></span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Border</span><span class="token style-attr language-css"><span class="token attr-name"> <span class="token attr-name">Style</span></span><span class="token punctuation">="</span><span class="token attr-value"><span class="token punctuation">{</span>StaticResource AddressItemStyle<span class="token punctuation">}</span></span><span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span> <span class="token attr-name">ColumnDefinitions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*,Auto<span class="token punctuation">"</span></span> <span class="token attr-name">ColumnSpacing</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>12<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                                    <span class="token comment">&lt;!--  Address Details  --&gt;</span>
                                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>VerticalStackLayout</span> <span class="token attr-name">Spacing</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span> <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Label</span>
                                            <span class="token attr-name">FontAttributes</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">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>15<span class="token punctuation">"</span></span>
                                            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding Label}<span class="token punctuation">"</span></span>
                                            <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#333333<span class="token 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">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>13<span class="token punctuation">"</span></span>
                                            <span class="token attr-name">LineBreakMode</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>TailTruncation<span class="token punctuation">"</span></span>
                                            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding FullAddress}<span class="token punctuation">"</span></span>
                                            <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#888888<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
                                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>VerticalStackLayout</span><span class="token punctuation">&gt;</span></span>

                                    <span class="token comment">&lt;!--  Selection Indicator  --&gt;</span>
                                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Border</span>
                                        <span class="token attr-name">Grid.Column</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding SelectionColor}<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">HeightRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>24<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">Stroke</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding SelectionBorderColor}<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">StrokeShape</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>RoundRectangle 12<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">StrokeThickness</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span>
                                        <span class="token attr-name">WidthRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>24<span class="token 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">FontSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>14<span class="token punctuation">"</span></span>
                                            <span class="token attr-name">HorizontalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Center<span class="token punctuation">"</span></span>
                                            <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{Binding CheckMark}<span class="token punctuation">"</span></span>
                                            <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>White<span class="token punctuation">"</span></span>
                                            <span class="token attr-name">VerticalOptions</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>Border</span><span class="token punctuation">&gt;</span></span>
                                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>
                            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Border</span><span class="token punctuation">&gt;</span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>DataTemplate</span><span class="token punctuation">&gt;</span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">telerik:</span>RadCollectionView.ItemTemplate</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">telerik:</span>RadCollectionView</span><span class="token punctuation">&gt;</span></span>

                <span class="token comment">&lt;!--  Action Buttons  --&gt;</span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>VerticalStackLayout</span> <span class="token attr-name">Grid.Row</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>3<span class="token punctuation">"</span></span> <span class="token attr-name">Spacing</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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><span class="token namespace">telerik:</span>RadButton</span>
                        <span class="token attr-name"><span class="token namespace">x:</span>Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>SelectAddressButton<span class="token punctuation">"</span></span>
                        <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#FB7647<span class="token punctuation">"</span></span>
                        <span class="token attr-name">Clicked</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>OnSelectAddressClicked<span class="token punctuation">"</span></span>
                        <span class="token attr-name">CornerRadius</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>12<span class="token punctuation">"</span></span>
                        <span class="token attr-name">FontAttributes</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">HeightRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>54<span class="token punctuation">"</span></span>
                        <span class="token attr-name">IsEnabled</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>False<span class="token punctuation">"</span></span>
                        <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Select Address<span class="token punctuation">"</span></span>
                        <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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><span class="token namespace">telerik:</span>RadButton</span>
                        <span class="token attr-name">BackgroundColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#4F3F9B<span class="token punctuation">"</span></span>
                        <span class="token attr-name">Clicked</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>OnAddNewAddressClicked<span class="token punctuation">"</span></span>
                        <span class="token attr-name">CornerRadius</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>12<span class="token punctuation">"</span></span>
                        <span class="token attr-name">FontAttributes</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">HeightRequest</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>54<span class="token punctuation">"</span></span>
                        <span class="token attr-name">Text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Add new address<span class="token punctuation">"</span></span>
                        <span class="token attr-name">TextColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>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>VerticalStackLayout</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>            
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">telerik:</span>RadBottomSheet.BottomSheetContent</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">telerik:</span>RadBottomSheet</span><span class="token punctuation">&gt;</span></span>        
</code></pre><p>With the above code, we have prepared the Bottom Sheet content to be displayed to the user when we indicate it.</p><h2 id="showing-the-bottomsheet-to-the-user">Showing the BottomSheet to the User</h2><p>Once we have the content of the Bottom Sheet ready, the next step is to display it.</p><p>There are several ways to achieve this; we will use the method <code>GoToBottomSheetState</code>, which allows for transitioning to a specific state. A state refers to how much screen space the Bottom Sheet will occupy, with possible values being <code>Hidden</code> (default), <code>Minimal</code> (25%), <code>Partial</code> (50%) and <code>Full</code> (90%). It is also possible to create <a target="_blank" href="https://www.telerik.com/maui-ui/documentation/controls/bottomsheet/configuration#custom-states">custom states</a>.</p><p>Knowing the above, in my example I will use the <code>TapGestureRecognizer</code>, which is part of the container that displays the current address, to show the Bottom Sheet from there:</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">OnAddressTapped</span><span class="token punctuation">(</span><span class="token keyword">object</span> sender<span class="token punctuation">,</span> EventArgs e<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
   AddressBottomSheet<span class="token punctuation">.</span><span class="token function">GoToBottomSheetState</span><span class="token punctuation">(</span>BottomSheetState<span class="token punctuation">.</span>FullState<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>In the same way that the Bottom Sheet can be shown at will, it can also be hidden using the same method, <code>GoToBottomSheetState</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">OnCloseBottomSheet</span><span class="token punctuation">(</span><span class="token keyword">object</span> sender<span class="token punctuation">,</span> EventArgs e<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
   AddressBottomSheet<span class="token punctuation">.</span><span class="token function">GoToBottomSheetState</span><span class="token punctuation">(</span>BottomSheetState<span class="token punctuation">.</span>HiddenState<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>The execution of the above changes results in the following:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/bottomsheet-control-in-action-allowing-users-to-select-a-different-delivery-address-for-an-order.gif?sfvrsn=2e2648cc_2" alt="BottomSheet control in action, allowing users to select a different delivery address for an order" /></p><p>In the image above, you can see how it is possible to select a different address thanks to the use of the Bottom Sheet, with a spectacular appearance, all without leaving the current window.</p><h2 id="customizing-the-bottom-sheet">Customizing the Bottom Sheet</h2><p>The Telerik BottomSheet control for .NET MAUI offers several properties that allow for the customization of the control. For example, the property <code>Width</code> allows you to specify the horizontal space that the Bottom Sheet will occupy, either through an absolute value or a percentage:</p><p><img src="https://www.telerik.com/maui-ui/documentation/assets/857c771af2dd2af7a4d8c510d3ddd8a0/bottomsheet-width.gif" alt="Demonstration of horizontal size adjustment of the Bottom Sheet using the Width property" /></p><p>Similarly, if you want to prevent the user from dragging up or down on the BottomSheet Handle, you can configure the property <code>IsSwipeEnabled</code> with a value <code>false</code>.</p><p>In addition, it is also possible to modify the animation of the Bottom Sheet, enabling or disabling it with the property <code>IsAnimationEnabled</code>, and adjusting both the duration of the animation and the easing function used through the properties <code>AnimationDuration</code> and <code>AnimationEasing</code>.</p><p>You can also change features such as the border, corner radius and background color of the Bottom Sheet through the property <code>BottomSheetContentStyle</code>. Additionally, you can modify the properties of the BottomSheet Handle using the property <code>HandleStyle</code>.</p><p>Below, I show you an example of the aforementioned properties applied to the Bottom Sheet:</p><pre class=" language-xml"><code class="prism  language-xml">
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ContentPage...</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ContentPage.Resources</span><span class="token punctuation">&gt;</span></span>
        <span class="token comment">&lt;!--  BottomSheet Content Style  --&gt;</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Style</span> <span class="token attr-name"><span class="token namespace">x:</span>Key</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>BottomSheetContentStyle<span class="token punctuation">"</span></span> <span class="token attr-name">TargetType</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>telerik:BottomSheetContentView<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token style language-css">
            &lt;Setter Property=<span class="token string">"BackgroundColor"</span> Value=<span class="token string">"#F7F7F7"</span> /&gt;
            &lt;Setter Property=<span class="token string">"CornerRadius"</span> Value=<span class="token string">"25,25,0,0"</span> /&gt;
            &lt;Setter Property=<span class="token string">"BorderColor"</span> Value=<span class="token string">"#4F3F9B"</span> /&gt;
            &lt;Setter Property=<span class="token string">"BorderThickness"</span> Value=<span class="token string">"5"</span> /&gt;
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Style</span><span class="token punctuation">&gt;</span></span>

        <span class="token comment">&lt;!--  BottomSheet Handle Style  --&gt;</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Style</span> <span class="token attr-name"><span class="token namespace">x:</span>Key</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>HandleStyle<span class="token punctuation">"</span></span> <span class="token attr-name">TargetType</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>telerik:BottomSheetHandle<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token style language-css">
            &lt;Setter Property=<span class="token string">"BackgroundColor"</span> Value=<span class="token string">"#4F3F9B"</span> /&gt;
            &lt;Setter Property=<span class="token string">"HeightRequest"</span> Value=<span class="token string">"5"</span> /&gt;
            &lt;Setter Property=<span class="token string">"WidthRequest"</span> Value=<span class="token string">"60"</span> /&gt;
            &lt;Setter Property=<span class="token string">"CornerRadius"</span> Value=<span class="token string">"3"</span> /&gt;
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Style</span><span class="token punctuation">&gt;</span></span>
        ...
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ContentPage.Resources</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">telerik:</span>RadBottomSheet</span>
        <span class="token attr-name"><span class="token namespace">x:</span>Name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>AddressBottomSheet<span class="token punctuation">"</span></span>
        <span class="token attr-name">AnimationDuration</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>300<span class="token punctuation">"</span></span>
        <span class="token attr-name">AnimationEasing</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{x:Static Easing.CubicOut}<span class="token punctuation">"</span></span>
        <span class="token attr-name">BottomSheetContent</span><span class="token style-attr language-css"><span class="token attr-name"><span class="token attr-name">Style</span></span><span class="token punctuation">="</span><span class="token attr-value"><span class="token punctuation">{</span>StaticResource BottomSheetContentStyle<span class="token punctuation">}</span></span><span class="token punctuation">"</span></span>
        <span class="token attr-name">BottomSheetContentWidth</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>100%<span class="token punctuation">"</span></span>
        <span class="token attr-name">Handle</span><span class="token style-attr language-css"><span class="token attr-name"><span class="token attr-name">Style</span></span><span class="token punctuation">="</span><span class="token attr-value"><span class="token punctuation">{</span>StaticResource HandleStyle<span class="token punctuation">}</span></span><span class="token punctuation">"</span></span>
        <span class="token attr-name">IsAnimationEnabled</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">IsSwipeEnabled</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">State</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Hidden<span class="token punctuation">"</span></span>
        <span class="token attr-name">StateChanging</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>OnBottomSheetStateChanging<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        ...
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">telerik:</span>RadBottomSheet</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ContentPage</span><span class="token punctuation">&gt;</span></span>    
</code></pre><p>The result of executing with the previous changes applied provides greater customization of the Bottom Sheet:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/customization-of-the-bottom-sheet-and-the-bottom-sheet-handle.png?sfvrsn=96d75829_2" alt="Customization of the Bottom Sheet and the Bottom Sheet handle" /></p><p>With this, we achieve a visual improvement that better centers the user on the content of the Bottom Sheet.</p><h2 id="conclusion">Conclusion</h2><p>Throughout this article, you have learned about the BottomSheet component of the Telerik UI for .NET MAUI control suite, understanding its purpose and how to customize it to show users additional options without leaving the current screen.</p><p>Undoubtedly, adding this type of component to your applications can enhance the user experience by allowing them to perform quick actions or obtain information easily.</p><p>Want to try this out for yourself? Telerik UI for Blazor comes with a free 30-day trial. </p><p><a href="https://www.telerik.com/try/ui-for-maui" target="_blank" class="Btn">Download Now</a></p>]]></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-06T02:18:19Z</updated>
    <author>
      <name>Peter Vogel </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/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>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:ca0196d4-deec-4d1b-864a-bee247a57fd4</id>
    <title type="text">Learning Vercel AI SDK—Part 1</title>
    <summary type="text">Learn how to set up a Vercel AI SDK project, install required dependencies and work with prompts, models and streaming.</summary>
    <published>2026-03-20T15:59:09Z</published>
    <updated>2026-04-06T02:18:19Z</updated>
    <author>
      <name>Dhananjay Kumar </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/learning-vercel-ai-sdk-part-1"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn how to set up a Vercel AI SDK project, install required dependencies and work with prompts, models and streaming.</span></p><p>The AI SDK is a robust TypeScript library that enables developers to easily create AI-powered applications. In this tutorial, you&rsquo;ll build a simple AI chatbot with a real-time streaming interface.</p><p>To follow this tutorial, verify:</p><ul><li>You have the latest version of <a href="https://nodejs.org/en">Node.js installed</a>.</li><li>You have an <a href="https://platform.openai.com/settings/organization/api-keys">OpenAI API key</a>.</li></ul><p>After completing this article, you will have a solid grasp of key concepts used in the Vercel AI SDK, including:</p><ul><li>Models</li><li>Text prompts</li><li>System prompts</li><li>Text generation</li><li>Text streaming</li></ul><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.<br />For that, in your terminal, run the following commands:</p><ul><li><code>npm install -D typescript @types/node ts-node</code></li><li><code>npx tsc &ndash;init</code></li></ul><p>Once the commands have been executed, replace the contents of your <strong>tsconfig.json</strong> 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 ai@beta @ai-sdk/openai@beta zod</li><li>npm install -D @types/node tsx typescript</li><li>npm i --save-dev @types/json-schema</li></ul><p>Next, add the <strong>.env file</strong> 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 <strong>package.json</strong> 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">"demo1"</span><span class="token punctuation">,</span>
  <span class="token string">"version"</span><span class="token punctuation">:</span> <span class="token string">"1.0.0"</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">"author"</span><span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
  <span class="token string">"license"</span><span class="token punctuation">:</span> <span class="token string">"ISC"</span><span class="token punctuation">,</span>
  <span class="token string">"description"</span><span class="token punctuation">:</span> <span class="token string">""</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">"^24.7.2"</span><span class="token punctuation">,</span>
    <span class="token string">"tsx"</span><span class="token punctuation">:</span> <span class="token string">"^4.20.6"</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.0-beta.29"</span><span class="token punctuation">,</span>
    <span class="token string">"ai"</span><span class="token punctuation">:</span> <span class="token string">"^6.0.0-beta.47"</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.1.12"</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><h2 id="generating-text">Generating Text</h2><p>Using the Vercel AI SDK, you can generate responses from an LLM in just a few lines of code. Call the <strong>generateText</strong> method, passing the model name and your desired prompt.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">const</span> model <span class="token operator">=</span> <span class="token function">openai</span><span class="token punctuation">(</span><span class="token string">"gpt-3.5-turbo"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> chat <span class="token operator">=</span> <span class="token keyword">async</span><span class="token punctuation">(</span>prompt<span class="token punctuation">:</span> <span class="token keyword">string</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> text <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">generateText</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        model<span class="token punctuation">,</span>
        prompt
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token keyword">return</span> text<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">chat</span><span class="token punctuation">(</span><span class="token string">"what is value of pi ?"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Result: "</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>As shown above, we have defined a model and passed it to the <code>generateText</code> function. The Vercel AI SDK makes it simple to integrate models from multiple providers. For instance, if you want to use a model other than OpenAI&rsquo;s GPT-3.5, declare that model and pass it to the <code>generateText</code> function. Verify that the corresponding provider dependency is installed in your project.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">const</span> model  <span class="token operator">=</span> <span class="token function">anthropic</span><span class="token punctuation">(</span><span class="token string">"claude-2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><h2 id="streaming-text">Streaming Text</h2><p>The Vercel AI SDK makes it simple to stream generated text token-by-token. To stream the response, use the <code>streamText</code> function.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">const</span> chat <span class="token operator">=</span> <span class="token keyword">async</span><span class="token punctuation">(</span>prompt<span class="token punctuation">:</span> <span class="token keyword">string</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> textStream <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">streamText</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        model<span class="token punctuation">,</span>
        prompt
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> textStream<span class="token punctuation">;</span> 
   
<span class="token punctuation">}</span>
</code></pre><p>The <code>streamText</code> function returns a <code>textStream</code> that you can iterate over using an await for loop to process the response chunk by chunk. Here, we&rsquo;re printing each chunk to the console, but you could also stream it to a client or save it to a file.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">chat</span><span class="token punctuation">(</span><span class="token string">"what is value of pi ?"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token keyword">await</span> <span class="token punctuation">(</span><span class="token keyword">const</span> chunk <span class="token keyword">of</span> result<span class="token punctuation">)</span> <span class="token punctuation">{</span>
     process<span class="token punctuation">.</span>stdout<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span>chunk<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Along with the text stream, the <code>streamText</code> function provides other useful properties like:</p><ul><li>content</li><li>text</li><li>reasoningText</li><li>etc.</li></ul><p>Here&rsquo;s an example of how you can use the content property:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">const</span> chat <span class="token operator">=</span> <span class="token keyword">async</span><span class="token punctuation">(</span>prompt<span class="token punctuation">:</span> <span class="token keyword">string</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> content <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">streamText</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        model<span class="token punctuation">,</span>
        prompt
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> content<span class="token punctuation">;</span> 
   
<span class="token punctuation">}</span>

<span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">chat</span><span class="token punctuation">(</span><span class="token string">"what is value of pi ?"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Result is : "</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>You should get output as shown below:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/content-property-output.png?sfvrsn=b81344b9_2" alt="text: The value of pi is approximately 3.14159…" /></p><h2 id="streaming-text-with-image-prompt">Streaming Text with Image Prompt</h2><p>The Vercel AI SDK provides a simple API for sending image inputs to multimodal models such as OpenAI&rsquo;s GPT-4o. By setting the message type to image, you can include an image in your prompt and receive a corresponding model-generated response.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">const</span> model <span class="token operator">=</span> <span class="token function">openai</span><span class="token punctuation">(</span><span class="token string">"gpt-4o"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">readImage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token function">streamText</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    model<span class="token punctuation">:</span> model<span class="token punctuation">,</span>
    messages<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 punctuation">[</span>
          <span class="token punctuation">{</span> <span class="token keyword">type</span><span class="token punctuation">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> <span class="token string">'Describe the image in detail.'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">{</span> <span class="token keyword">type</span><span class="token punctuation">:</span> <span class="token string">'image'</span><span class="token punctuation">,</span> image<span class="token punctuation">:</span> fs<span class="token punctuation">.</span><span class="token function">readFileSync</span><span class="token punctuation">(</span><span class="token string">'./m.jpg'</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><span class="token punctuation">;</span>

  <span class="token keyword">for</span> <span class="token keyword">await</span> <span class="token punctuation">(</span><span class="token keyword">const</span> textPart <span class="token keyword">of</span> result<span class="token punctuation">.</span>textStream<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    process<span class="token punctuation">.</span>stdout<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span>textPart<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token function">readImage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In the example above, both text and image inputs are sent to the multimodal model <strong>OpenAI&rsquo;s GPT-4o</strong>. The model then streams a response that describes and explains the provided image.</p><p>For the above example, you should get a response as below:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/image-described.png?sfvrsn=ac012f06_2" alt="The image showcases a breathtaking mountain landscape… description goes on for three paragraphs." /></p><h2 id="different-types-of-prompts">Different Types of Prompts</h2><p>Prompts are the instructions provided to an LLM that define what task it should perform. Each LLM supports different message formats for handling these instructions. The Vercel AI SDK offers a simplified abstraction over these formats, providing a unified interface for working with multiple model providers. It mainly supports three types of prompts:</p><ol><li>Text Prompts</li><li>Message Prompts</li><li>System Prompts</li></ol><p>A <strong>text prompt</strong> is a simple string that serves as input to the model. This format is ideal for straightforward generation tasks, such as producing variations of a specific message or pattern.</p><p>In the Vercel AI SDK, you can define a text prompt using the prompt property in functions such as <code>generateText</code> or <code>streamText</code>. As shown in the example below, the string prompt is passed directly to the prompt property of the <code>generateText</code> function.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">const</span> chat <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">const</span> <span class="token punctuation">{</span> text <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">generateText</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        model<span class="token punctuation">,</span>
        prompt<span class="token punctuation">:</span><span class="token string">'What is value of pi ?'</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token keyword">return</span> text<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>You can also use template literals to pass dynamic values into a text prompt. This approach allows you to create flexible and reusable prompts for your models, as shown in the example below.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">const</span> model <span class="token operator">=</span> <span class="token function">openai</span><span class="token punctuation">(</span><span class="token string">"gpt-4o"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> chat <span class="token operator">=</span> <span class="token keyword">async</span><span class="token punctuation">(</span>days<span class="token punctuation">:</span><span class="token keyword">number</span><span class="token punctuation">,</span> destination<span class="token punctuation">:</span><span class="token keyword">string</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> text <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">generateText</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        model<span class="token punctuation">,</span>
        prompt<span class="token punctuation">:</span><span class="token template-string"><span class="token string">`Give me </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>days<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> days vacation plan in </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>destination<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">return</span> text<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">chat</span><span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token string">"Egypt"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Result is : "</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In this example, the number of days and the country name are dynamically passed to the text prompt to generate a context-specific response from the model.</p><p>A <strong>system prompt</strong> provides high-level guidance that shapes the chat model&rsquo;s behavior during a conversation.</p><ul><li>It instructs the model on how to respond.</li><li>It establishes rules and constraints for interaction.</li><li>It sets the tone, style and personality of the responses.</li></ul><p>You can define a system prompt using the system property. In the example below, the model is instructed to provide travel suggestions in a list format.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">const</span> model <span class="token operator">=</span> <span class="token function">openai</span><span class="token punctuation">(</span><span class="token string">"gpt-4o"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> system <span class="token operator">=</span> <span class="token template-string"><span class="token string">`You are a travel assistant. 
You help users plan their vacations by providing detailed itineraries based 
on the number of days and destination they provide. Your responses should include 
daily activities, places to visit, and any special tips for travelers.`</span></span>

<span class="token keyword">export</span> <span class="token keyword">const</span> chat <span class="token operator">=</span> <span class="token keyword">async</span><span class="token punctuation">(</span>days<span class="token punctuation">:</span><span class="token keyword">number</span><span class="token punctuation">,</span> destination<span class="token punctuation">:</span><span class="token keyword">string</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> text <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">generateText</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        model<span class="token punctuation">,</span>
        system<span class="token punctuation">:</span> system<span class="token punctuation">,</span>
        prompt<span class="token punctuation">:</span><span class="token template-string"><span class="token string">`Give me </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>days<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> days vacation plan in </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>destination<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">return</span> text<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">chat</span><span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token string">"Egypt"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Result is : "</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The model&rsquo;s response should follow the instructions defined in the system prompt. Let&rsquo;s look at another example of a system prompt. In this case, we instruct the model to:</p><ul><li>Respond only with information related to <strong>India</strong>.</li><li>Provide the response in <strong>JSON format</strong>.</li><li>For any question unrelated to India, reply that it can only answer questions about India.</li></ul><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">const</span> model <span class="token operator">=</span> <span class="token function">openai</span><span class="token punctuation">(</span><span class="token string">"gpt-4o"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> system <span class="token operator">=</span> <span class="token template-string"><span class="token string">`You only answer about India in JSON Format. 
Any question not related to India should be answered with
{"message": "I can only answer questions related to India"}
`</span></span>

<span class="token keyword">export</span> <span class="token keyword">const</span> chat <span class="token operator">=</span> <span class="token keyword">async</span><span class="token punctuation">(</span>question <span class="token punctuation">:</span> <span class="token keyword">string</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> text <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">generateText</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        model<span class="token punctuation">,</span>
        system<span class="token punctuation">:</span> system<span class="token punctuation">,</span>
        prompt<span class="token punctuation">:</span>question
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token keyword">return</span> text<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">let</span> prompt <span class="token operator">=</span> <span class="token string">"Tell me about the capital of India"</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">chat</span><span class="token punctuation">(</span>prompt<span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Result is : "</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> prompt2 <span class="token operator">=</span> <span class="token string">"Tell me about the capital of USA"</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> result1 <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">chat</span><span class="token punctuation">(</span>prompt2<span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Result is : "</span><span class="token punctuation">,</span> result1<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>For above queries, model should give response as shown below:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/query-responses-india.png?sfvrsn=a2e483e7_2" alt="capital: New Delhi, established: 1911, etc." /></p><h2 id="a-chat-app">A Chat App</h2><p>Bringing everything together, you can build a chat application that uses text prompts, system prompts and other prompt types, as shown in the code example below.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> openai <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@ai-sdk/openai'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> generateText <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> 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> model <span class="token operator">=</span> <span class="token function">openai</span><span class="token punctuation">(</span><span class="token string">"gpt-4o"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> system <span class="token operator">=</span> <span class="token template-string"><span class="token string">`You only answer about India and USA. 
Any question not related to India and USA should be answered with
sorry I know only about India and USA`</span></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> chat <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span>question<span class="token punctuation">:</span> <span class="token keyword">string</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> text <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">generateText</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        model<span class="token punctuation">,</span>
        system<span class="token punctuation">:</span> system<span class="token punctuation">,</span>
        prompt<span class="token punctuation">:</span> question
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> text<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> getInput <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> Promise<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token operator">&gt;</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span>resolve<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        process<span class="token punctuation">.</span>stdout<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span><span class="token string">'Enter your question (or "q" to quit): '</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        process<span class="token punctuation">.</span>stdin<span class="token punctuation">.</span><span class="token function">once</span><span class="token punctuation">(</span><span class="token string">'data'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>data<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            <span class="token function">resolve</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">trim</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>

<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Welcome to AI Chat! Ask questions about India and USA.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Type "q" to quit.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'-------------------'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    process<span class="token punctuation">.</span>stdin<span class="token punctuation">.</span><span class="token function">setEncoding</span><span class="token punctuation">(</span><span class="token string">'utf8'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token keyword">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token keyword">const</span> userInput <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getInput</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>userInput<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string">'q'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Goodbye!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                process<span class="token punctuation">.</span><span class="token function">exit</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            
            console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Thinking...'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">chat</span><span class="token punctuation">(</span>userInput<span class="token punctuation">)</span><span class="token punctuation">;</span>
            console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'AI Response:'</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
            console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'-------------------'</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">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'Error:'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>
            console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'-------------------'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token function">main</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>console<span class="token punctuation">.</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>When you run the application, the model should respond only to queries related to <strong>India</strong> or the <strong>USA</strong>. For any question outside these topics, the model should refrain from answering.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/query-responses-restricted.png?sfvrsn=993d66f_2" alt="When the user asks about the capital of France, the AI responds: Sorry, I know only about India and USA" /></p><p>As explained earlier, streaming model responses are straightforward with the Vercel AI SDK. You can use the <code>streamText</code> function to receive the output incrementally, as shown in the example below.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">const</span> chat <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span>question<span class="token punctuation">:</span> <span class="token keyword">string</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> textStream <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">streamText</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        model<span class="token punctuation">,</span>
        system<span class="token punctuation">:</span> system<span class="token punctuation">,</span>
        prompt<span class="token punctuation">:</span> question
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> textStream<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>wAnd then printing the response as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Thinking...'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">chat</span><span class="token punctuation">(</span>userInput<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// console.log('AI Response:', result);</span>
            <span class="token keyword">for</span> <span class="token keyword">await</span> <span class="token punctuation">(</span><span class="token keyword">const</span> chunk <span class="token keyword">of</span> result<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                process<span class="token punctuation">.</span>stdout<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span>chunk<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
</code></pre><h2 id="summary">Summary</h2><p>In this part of the Vercel AI SDK learning series, you learned how to set up the project, install the required dependencies and work with key concepts such as prompts, models and streaming. I hope you found this article helpful. Thank you for reading.</p><hr /><p><strong>Next up:</strong> <a href="https://www.telerik.com/blogs/learning-vercel-ai-sdk-part-2-creating-your-first-agent" target="_blank">Learning Vercel AI SDK&mdash;Part 2: Creating Your First Agent</a></p>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:4733c0a3-bf88-4efb-8d20-246db8da5688</id>
    <title type="text">The Great React Grid-Off: KendoReact vs. MUI vs. AG Grid</title>
    <summary type="text">Curious how the best React grids on the market compete head-to-head? KendoReact vs. MUI vs. AG Grid—let’s see it!</summary>
    <published>2026-03-19T20:15:24Z</published>
    <updated>2026-04-06T02:18:19Z</updated>
    <author>
      <name>Kathryn Grayson Nanz </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/great-react-grid-off-kendoreact-vs-mui-vs-ag-grid"/>
    <content type="text"><![CDATA[<p><span class="featured">Curious how the best React grids on the market compete head-to-head? KendoReact vs. MUI vs. AG Grid&mdash;let&rsquo;s see it!</span></p><p>If you&rsquo;re looking for an enterprise-level <a href="https://www.telerik.com/kendo-react-ui/components/grid" target="_blank">data grid for your React</a> application, there&rsquo;s no shortage of options to consider. When you&rsquo;re making a comparison, many aspects will be subjective; those things will ultimately come down to which approach makes the most sense to you as a developer and what you think will be easiest for your existing team to adopt.</p><p>However, there are also performance-related metrics that are objective, which we can test directly and draw clear conclusions around. In the hopes of making that task slightly easier for you, we ran the tests ourselves and would like to share the results.</p><p>This benchmark compares the rendering and virtualization performance of three popular React data grids: Progress KendoReact, MUI and AG Grid. The goal is to provide objective, repeatable performance data across common real-world scenarios&mdash;from small datasets to large, virtualized grids with up to 1 million rows. We wanted to mirror production-like situations as closely as possible, rather than simply testing demo scenarios that aren&rsquo;t commonly reflected in real applications.</p><h2 id="sneak-peek-at-the-results">Sneak Peek at the Results</h2><p>For those of you who are just eager to see our conclusions, below is a summary of our results. For those interested in diving deeper into the methodology and details, read on!</p><ul><li>For basic grids (&le;5k rows, no virtualization), MUI is faster.</li><li>When paging is enabled, the KendoReact consistently leads.</li><li>If virtualization is needed (10k&ndash;1M rows), KendoReact is significantly faster, with performance gaps widening as datasets grow.</li><li>In situations with row <em>and</em> column virtualization, MUI performs well on smaller datasets, while KendoReact scales better at higher volumes.</li><li>If you&rsquo;re working with very large datasets, the best choice is the KendoReact Data Grid.</li></ul><h2 id="how-we-measure-performance">How We Measure Performance</h2><p>Before we look at the numbers, let&rsquo;s take a second to discuss how we calculated them.</p><p>We run automated performance tests twice each week (for our own visibility) and track the results to a set of internal dashboards. This is for our own learning&mdash;we want to keep an eye on our grid and how it performs in real-world scenarios, as compared to our competitors. All our tests are designed to be repeatable and to reflect realistic application usage.</p><p>We run our tests via GitHub Actions, using Selenium WebDriver and a custom browser automation in a headless Chromium browser. The tests use realistic, production-like data generated with the Faker.js library (ours is for a &ldquo;warehouse,&rdquo; with columns for ID, name, price, start date, units in stock, discontinued status and a description). For tests requiring wider datasets, additional column content is dynamically generated, with each cell containing realistic five-character alphanumeric data. Each scenario is executed eight times, and we average the results for consistency.</p><p>The testing framework uses high-precision millisecond timing, moving through the following steps:</p><ol><li><strong>Pre-render State:</strong> To begin, the Grid component is <em>not</em> initially loaded on the page.</li><li><strong>Data Generation:</strong> Test data is generated and prepared in memory before timing begins.</li><li><strong>Timer Start:</strong> A precise timestamp is captured using <code>Date.now()</code> immediately before grid initialization.</li><li><strong>Grid Load:</strong> The Grid component is rendered with a full dataset.</li><li><strong>Completion Detection:</strong> Automated polling (every 10ms) detects when the last table cell becomes visible in the DOM using XPath selectors (<code>td[contains(@class,'k-table-td')]</code>).</li><li><strong>Timer Stop:</strong> A timestamp is captured when the target cell is detected.</li><li><strong>Result:</strong> The rendering time in milliseconds is logged.</li></ol><h2 id="what-gets-measured">What Gets Measured</h2><p>We look at our KendoReact Data Grid (Premium) as compared to AG Grid (Community Edition) and MUI Grid (Material-UI Data Grid) in terms of pure component rendering time, DOM manipulation performance, virtual scrolling efficiency and template rendering overhead. We do not measure network latency, API calls or data generation time.</p><p>For all the grids, we test in four different configurations:</p><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 <tr><th style="width:25%;padding:5px;"><strong>Scenario</strong></th><th style="width:25%;padding:5px;"><strong>Rows</strong></th><th style="width:25%;padding:5px;"><strong>Columns</strong></th><th style="width:25%;padding:5px;"><strong>Features</strong></th></tr></thead><tbody><tr><td style="width:25%;padding:5px;"><strong>Basic Grid (no virtualization)</strong></td><td style="width:25%;padding:5px;">5,000</td><td style="width:25%;padding:5px;">20</td><td style="width:25%;padding:5px;">Sorting and Filtering</td></tr><tr><td style="width:25%;padding:5px;"><strong>Paged Grid (no virtualization)</strong></td><td style="width:25%;padding:5px;">5,000</td><td style="width:25%;padding:5px;">20</td><td style="width:25%;padding:5px;">Sorting, Filtering, Paging</td></tr><tr><td style="width:25%;padding:5px;"><strong>Row Virtualization</strong></td><td style="width:25%;padding:5px;">1,000,000</td><td style="width:25%;padding:5px;">10</td><td style="width:25%;padding:5px;">Sorting, Filtering, Row Virtualization</td></tr><tr><td style="width:25%;padding:5px;"><strong>Row + Column Virtualization</strong></td><td style="width:25%;padding:5px;">100,000</td><td style="width:25%;padding:5px;">100</td><td style="width:25%;padding:5px;">Sorting, Filtering, Dual-Axis Virtualization</td></tr></tbody></table><br /><h2 id="the-results-in-detail">The Results in Detail</h2><p>Now that the scope and scale of the tests have been established, let&rsquo;s look at the results. This particular benchmark compared KendoReact v13.0.0 against AG Grid Community v34.3.1 and MUI Grid v8.11.0. <strong>Below are the results from this specific test, but it&rsquo;s worth noting that we repeat these tests regularly and the results are consistently similar.</strong></p><h3 id="grid-basic-tests">Grid Basic Tests</h3><h4 id="rows-x-10-cols">100 Rows x 10 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><style>table,
 th,
        td {
            border: 1px;
            border-color: #bdbdba;
            border-style: dotted;
            border-collapse: collapse;
            margin-right: auto;
            text-align: left;
        }
    </style>
 <thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>MUI</td><td>671.00ms</td></tr><tr><td>KendoReact</td><td>709.00ms</td></tr><tr><td>AG Grid</td><td>841.25ms</td></tr></tbody></table><br /><h4 id="rows-x-100-cols">100 Rows x 100 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>MUI</td><td>1762.88ms</td></tr><tr><td>AG Grid</td><td>1817ms</td></tr><tr><td>KendoReact</td><td>1998.00ms</td></tr></tbody></table><br /><h4 id="rows-x-10-cols-1">1,000 Rows x 10 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>AG Grid</td><td>2133.63ms</td></tr><tr><td>MUI</td><td>2364.25ms</td></tr><tr><td>KendoReact</td><td>2475.88ms</td></tr></tbody></table><br /><h4 id="rows-x-20-cols">5,000 Rows x 20 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>MUI</td><td>104004.25ms</td></tr><tr><td>KendoReact</td><td>14718.25ms</td></tr><tr><td>AG Grid</td><td>16494.63ms</td></tr></tbody></table><br /><h3 id="grid-paging-tests">Grid Paging Tests</h3><h4 id="rows-x-10-cols-2">100 Rows x 10 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>KendoReact</td><td>332.25ms</td></tr><tr><td>MUI</td><td>413.88ms</td></tr><tr><td>AG Grid</td><td>459.50ms</td></tr></tbody></table><br /><h4 id="rows-x-100-cols-1">100 Rows x 100 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>KendoReact</td><td>824.13ms</td></tr><tr><td>AG Grid</td><td>846.00ms</td></tr><tr><td>MUI</td><td>988.88ms</td></tr></tbody></table><br /><h4 id="rows-x-10-cols-3">1,000 Rows x 10 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>KendoReact</td><td>335.63ms</td></tr><tr><td>MUI</td><td>424.38ms</td></tr><tr><td>AG Grid</td><td>448.63ms</td></tr></tbody></table><br /><h4 id="rows-x-20-cols-1">5,000 Rows x 20 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>KendoReact</td><td>374.88ms</td></tr><tr><td>MUI</td><td>462.38ms</td></tr><tr><td>AG Grid</td><td>494.75ms</td></tr></tbody></table><br /><h3 id="column-virtualization-tests">Column Virtualization Tests</h3><h4 id="rows-x-100-cols-2">10,000 Rows x 100 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>MUI</td><td>489.13ms</td></tr><tr><td>AG Grid</td><td>495.88ms</td></tr><tr><td>KendoReact</td><td>763.25ms</td></tr></tbody></table><br /><h4 id="rows-x-100-cols-3">100,000 Rows x 100 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>KendoReact</td><td>621.25ms</td></tr><tr><td>AG Grid</td><td>847.75ms</td></tr><tr><td>MUI</td><td>1079.88ms</td></tr></tbody></table><br /><h3 id="dual-axis-virtualization-tests">Dual-Axis Virtualization Tests</h3><h4 id="rows-x-10-cols-4">10,000 Rows x 10 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>KendoReact</td><td>319.25ms</td></tr><tr><td>MUI</td><td>419.50ms</td></tr><tr><td>AG Grid</td><td>601.25ms</td></tr></tbody></table><br /><h4 id="rows-x-10-cols-5">100,000 Rows x 10 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>KendoReact</td><td>350.75ms</td></tr><tr><td>MUI</td><td>705.38ms</td></tr><tr><td>AG Grid</td><td>798.75ms</td></tr></tbody></table><br /><h4 id="rows-x-10-cols-6">1,000,000 Rows x 10 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>KendoReact</td><td>826.63ms</td></tr><tr><td>MUI</td><td>5608.38ms</td></tr><tr><td>AG Grid</td><td>5974.25ms</td></tr></tbody></table><br /><h3 id="basic-grid">Basic Grid</h3><p>For the Basic Grid, MUI came out on top&mdash;although, it&rsquo;s worth remembering that in all these situations, we&rsquo;re talking about a matter of milliseconds (note that I&rsquo;ve converted the results into seconds in these summaries, since that&rsquo;s a bit easier to mentally parse). Still, they consistently clocked in faster than both KendoReact and AG Grid.</p><p>For a 100x10 grid, MUI (0.67s) was faster than KendoReact (0.71s) and AG Grid (0.85s). Even at 5,000x20, MUI (10.4s) still kept the lead over both KendoReact (14.7s) and AG Grid (16.5s).</p><p><strong>For small datasets without virtualization, MUI Grid shows slightly faster initial render times, though all three grids perform within the same order of magnitude.</strong></p><h3 id="paging">Paging</h3><p>The situation changes once other, more complicated factors are included. When we enable paging, we see KendoReact move into the lead.</p><p>In a 100x10 grid, KendoReact (0.33s) is faster than MUI (0.41s) and AG Grid (0.46s). Scaled up to a 5,000x20 grid, KendoReact (0.38s) still has the edge on MUI (0.46s), which in turn beats out AG Grid (0.50s).</p><p><strong>Once paging is enabled, the KendoReact Grid consistently outperforms both MUI Grid and AG Grid across all tested dataset sizes.</strong></p><h3 id="row-virtualization">Row Virtualization</h3><p>Similarly, KendoReact remains on top for row virtualization. For a 10,000x10 grid, KendoReact (0.32s) is more performant than both MUI (0.42s) and AG Grid (0.60s).</p><p>Push that to 1,000,000x10, and we start to see a truly significant difference: KendoReact (0.83s) is significantly faster than MUI (5.6s) and AG Grid (6s). Obviously, that&rsquo;s a testing scenario that pushes the boundaries of capability, but it demonstrates the kind of compounding performance costs that developers need to be aware of when dealing with larger datasets.</p><p><strong>As dataset size increases, performance gaps widen significantly. At 1,000,000 rows, KendoReact renders in under 1 second, while MUI Grid and AG Grid require more than 5 seconds.</strong></p><h3 id="row--column-virtualization">Row + Column Virtualization</h3><p>MUI and KendoReact split the victory on Row + Column Virtualization.</p><p>When we tested with a smaller dataset, MUI takes the lead: at 10,000x100, MUI (0.49s) is faster than AG Grid (0.5s), which is faster than KendoReact (0.77s).</p><p>However, KendoReact takes the crown when tested with the larger dataset: at 100,000x100, KendoReact (0.62s) beats AG Grid (0.85s) and MUI (1.1s).</p><p><strong>KendoReact scales more predictably as both row and column counts grow, avoiding compounding render costs.</strong></p><h2 id="which-grid-is-best-for-your-team">Which Grid Is Best for Your Team?</h2><p>There&rsquo;s a long-running joke: no matter what they&rsquo;re asked, a senior developer never says &ldquo;yes&rdquo; or &ldquo;no&rdquo; They always say: &ldquo;It depends.&rdquo;</p><p>I must be showing my true colors here, because when faced with the question of which grid to pick, I find myself saying &hellip; well, it depends!</p><p><strong>You might prefer MUI Grid if:</strong></p><ul><li>Your datasets are small</li><li>You prioritize Material UI consistency</li><li>You rarely rely on virtualization</li></ul><p><strong>You might prefer KendoReact Grid if:</strong></p><ul><li>Your app handles large or growing datasets</li><li>Virtualization and performance are top priorities</li><li>You need predictable enterprise-grade performance at scale</li></ul><p>If you just need basic grid functionality, all the grids we looked at here were honestly pretty evenly matched in terms of performance.</p><p>In this case, as a tech lead, I would default to other determining factors to help tip the scales. What other components are included in the library that could be leveraged in our app? How does it meet the needs of our users who rely on accessibility functionality? How customizable is it? How easy is it to integrate AI-related functionality? How often is it updated, and what are the available customer support offerings?</p><p>How you weigh and compare the answers to these questions will ultimately come down to what factors are most important for both the userbase of your specific application and the needs of your specific team.</p><p>However, if you&rsquo;re dealing with truly large datasets and virtualization is a high priority, then KendoReact is the frontrunner. And the larger the dataset gets, the greater the disparity between KendoReact and the competitors.</p><p>If your application needs to handle truly large amounts of data, there&rsquo;s one grid that&rsquo;s simply better equipped to do so: the KendoReact Data Grid.</p><h2 id="try-it-yourself">Try It Yourself!</h2><p>Of course, we highly encourage you to try this experiment for yourself! That&rsquo;s why we shared our methodology: this is meant to be repeatable and standardized. If you run these tests and see different results, please let us know.</p><p>You can even try the full KendoReact library free for 30 days:</p><p><a target="_blank" href="https://www.telerik.com/try/kendo-react-ui" class="Btn">Try KendoReact</a></p>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:87c10f2e-3ade-44b2-83f9-6149d2739d34</id>
    <title type="text">10+ Learning Resources to Kick-Start Your AI Journey</title>
    <summary type="text">These 10+ resources can help you learn how to get started with AI as a developer.</summary>
    <published>2026-03-19T15:49:53Z</published>
    <updated>2026-04-06T02:18:19Z</updated>
    <author>
      <name>Ed Charbeneau </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/learning-resources-kick-start-your-ai-journey"/>
    <content type="text"><![CDATA[<p><span class="featured">These 10+ resources can help you learn how to get started with AI as a developer.</span></p><p>Getting started with AI doesn&rsquo;t require a PhD, but it does require the right mix of fundamentals, intuition and practical exposure. The following resources strike that balance, giving developers a clear path from curiosity to capability.</p><h2 id="nvidia-ai-learning-essentials">1. NVIDIA AI Learning Essentials</h2><p><a target="_blank" href="https://www.nvidia.com/en-us/learn/ai-learning-essentials/">https://www.nvidia.com/en-us/learn/ai-learning-essentials/</a><br /><strong>Labels:</strong> Free, For Developers, Structured Learning
</p><p>NVIDIA delivers a structured, developer-friendly introduction to AI, covering everything from machine learning basics to deep learning workflows.</p><p>As powerful as it is convenient, this resource provides a guided path that keeps concepts grounded in real-world application.</p><h2 id="anthropic-learn-ai">2. Anthropic Learn AI</h2><p><a target="_blank" href="https://www.anthropic.com/learn">https://www.anthropic.com/learn</a><br /><strong>Labels:</strong> Free, For Developers, Conceptual
</p><p>Anthropic focuses on modern AI systems, including large language models (LLMs) and responsible AI practices. The material is concise, current and aligned with how AI is evolving today.</p><p>This is where foundational concepts meet real-world relevance.</p><h2 id="andrej-karpathy’s-ai-resources">3. Andrej Karpathy&rsquo;s AI Resources</h2><p><a target="_blank" href="https://karpathy.ai/">https://karpathy.ai/</a><br /><strong>Labels:</strong> Free, Deep Dives, For Developers
</p><p>Karpathy&rsquo;s work stands out for its ability to connect theory with implementation. Neural networks, training loops and model behavior are explained in a way that resonates with engineers.</p><p>This is where developers move beyond using AI and begin to understand it.</p><h2 id="blue1brown-youtube">4. 3Blue1Brown (YouTube)</h2><p><a target="_blank" href="https://www.youtube.com/@3blue1brown">https://www.youtube.com/@3blue1brown</a><br /><strong>Labels:</strong> Free, Conceptual, Deep Dives
</p><p>3Blue1Brown transforms complex math into visual intuition. Topics like neural networks and gradients become approachable through clear, animated explanations.</p><p>With this level of clarity, abstract concepts start to feel practical.</p><h2 id="ibm-technology-youtube">5. IBM Technology (YouTube)</h2><p><a target="_blank" href="https://www.youtube.com/@IBMTechnology">https://www.youtube.com/@IBMTechnology</a><br /><strong>Labels:</strong> Free, For Developers, Industry Perspective
</p><p>IBM&rsquo;s channel bridges the gap between theory and enterprise use. It covers AI concepts, tooling and infrastructure with a focus on real-world adoption.</p><p>This is where AI is placed into the context of systems developers already understand.</p><h2 id="everyday-ai-youtube">6. Everyday AI (YouTube)</h2><p><a target="_blank" href="https://www.youtube.com/@EverydayAI_">https://www.youtube.com/@EverydayAI</a>_<br /><strong>Labels:</strong> Free, Practical, Beginner-Friendly
</p><p>Everyday AI emphasizes applied workflows and tools. It highlights how AI is used in day-to-day scenarios, making it easier to translate knowledge into action.</p><p>The key takeaway is simple: knowing how to use AI is just as important as knowing how it works.</p><h2 id="burke-holland-youtube">7. Burke Holland (YouTube)</h2><p><a target="_blank" href="https://www.youtube.com/@BurkeHolland/featured">https://www.youtube.com/@BurkeHolland/featured</a><br /><strong>Labels:</strong> Free, For Developers, Practical
</p><p>Burke Holland&rsquo;s content brings a developer-first perspective to modern tooling, including AI-powered workflows. The focus is on practical productivity, integrating AI into real development environments and making sense of rapidly evolving tools.</p><p>This is where AI meets day-to-day developer experience, with an emphasis on getting real work done.</p><h2 id="dometrain-ai-courses">8. Dometrain AI Courses</h2><p><a target="_blank" href="https://dometrain.com/courses/?filters=ai">https://dometrain.com/courses/?filters=ai</a><br /><strong>Labels:</strong> Paid, For Developers, Deep Dives
</p><p>Dometrain offers in-depth, developer-focused courses that emphasize hands-on learning. The AI catalog includes practical training on building, integrating and deploying AI-powered applications.</p><p>The key to its success is its focus on real implementation. Developers are not just learning concepts, they are building solutions.</p><h2 id="telerik-ai-blog">9. Telerik AI Blog</h2><p><a target="_blank" href="https://www.telerik.com/blogs/artificial-intelligence">https://www.telerik.com/blogs/artificial-intelligence</a><br /><strong>Labels:</strong> Free, For Developers, Practical, Industry Perspective
</p><p>The Progress Telerik AI blog provides developer-focused insights into how AI is being applied in modern applications. Topics range from integrating AI into UI workflows to exploring new tooling and frameworks.</p><p>This is where AI concepts are translated into practical guidance for building real-world applications.</p><h2 id="progress-data--ai-blog">10. Progress Data &amp; AI Blog</h2><p><a target="_blank" href="https://www.progress.com/blogs/data-and-ai">https://www.progress.com/blogs/data-and-ai</a><br /><strong>Labels:</strong> Free, For Developers, Industry Perspective, Practical
</p><p>The Progress Data &amp; AI blog expands on broader data and AI topics, offering insights into trends, architecture and implementation strategies. It connects AI with the larger data ecosystem, highlighting how systems, pipelines and applications come together.</p><p>With this perspective, AI becomes part of a bigger picture, one that developers can design, build and scale.</p><h2 id="microsoft-reactor">11. Microsoft Reactor</h2><p><a href="https://developer.microsoft.com/en-us/reactor/">https://developer.microsoft.com/en-us/reactor/</a><br /><strong>Labels:</strong> Free, For Developers, Live Learning, Community</p><p>Microsoft Reactor offers live and on-demand sessions covering AI, cloud and modern development practices. It brings together experts, community leaders and hands-on demos in an interactive format.</p><p>This is where learning becomes collaborative. Developers gain not just knowledge, but context from real-world discussions and evolving best practices.</p><h2 id="microsoft-learn-ai">12. Microsoft Learn AI</h2><p><a href="https://learn.microsoft.com/en-us/ai/">https://learn.microsoft.com/en-us/ai/</a><br /><strong>Labels:</strong> Free, For Developers, Structured Learning</p><p>Microsoft Learn provides a comprehensive AI learning path with modules, exercises and hands-on labs. It spans fundamentals through advanced topics, often integrated with Azure services.</p><p>This is where structured learning meets practical implementation at scale.</p><h2 id="google-ai">13. Google AI</h2><p><a href="https://ai.google/">https://ai.google/</a><br /><strong>Labels:</strong> Free, Conceptual, Industry Perspective</p><p>Google AI offers research insights, educational content and real-world applications of AI across products and services. It provides a broader view of how AI is shaping modern technology.</p><p>This is where innovation and research intersect with real-world impact.</p><h3 id="ai-explained-youtube">14. AI Explained (YouTube)</h3><p><a href="https://www.youtube.com/@aiexplained-official">https://www.youtube.com/@aiexplained-official</a><br /><strong>Labels:</strong> Free, Conceptual, Industry Perspective</p><p>AI Explained breaks down complex AI topics, trends and news into digestible insights. It is particularly useful for staying current with rapid advancements in the field.</p><p>This is where awareness of the AI landscape begins to take shape.</p><h2 id="bycloud-youtube">15. bycloud (YouTube)</h2><p><a href="https://www.youtube.com/@bycloudAI">https://www.youtube.com/@bycloudAI</a><br /><strong>Labels:</strong> Free, Practical, For Developers</p><p>bycloud focuses on hands-on AI applications, tools and workflows. Content often explores building with modern AI stacks and integrating APIs into real solutions.</p><p>This is where experimentation turns into working implementations.</p><h2 id="theo-browne-youtube">16. Theo Browne (YouTube)</h2><p><a href="https://www.youtube.com/@t3dotgg">https://www.youtube.com/@t3dotgg</a><br /><strong>Labels:</strong> Free, For Developers, Practical</p><p>Theo Browne brings a full-stack developer perspective to AI, often exploring how AI fits into modern web development workflows.</p><p>This is where AI integrates into the tools developers already use daily.</p><h2 id="matt-pocock-youtube--ai-hero">17. Matt Pocock (YouTube &amp; AI Hero)</h2><p><a href="https://www.youtube.com/@mattpocockuk">https://www.youtube.com/@mattpocockuk</a><br /><a href="https://www.aihero.dev/">https://www.aihero.dev/</a><br /><strong>Labels:</strong> Free, Paid, For Developers, Practical</p><p>Matt Pocock focuses on developer productivity, TypeScript, and modern tooling, with growing coverage of AI-assisted development. AI Hero complements this with structured learning content.</p><p>This is where strong developer fundamentals meet AI-enhanced workflows.</p><h2 id="sam-witteveen-youtube">18. Sam Witteveen (YouTube)</h2><p><a href="https://www.youtube.com/@samwitteveenai">https://www.youtube.com/@samwitteveenai</a><br /><strong>Labels:</strong> Free, Deep Dives, For Developers</p><p>Sam Witteveen provides deep technical explorations of LLMs, agents, and AI architectures. The content often includes hands-on walkthroughs and real implementations.</p><p>This is where developers dive deep into how modern AI systems are actually built.</p><h2 id="final-thoughts">Final Thoughts</h2><p>AI learning is not a single track. It is a layered experience.</p><p>Start with structured fundamentals, build intuition through visualization and reinforce everything with practical use. With that approach, AI becomes less about theory and more about capability.</p><p>And that shift is where real progress begins.</p><hr /><blockquote><p>Let us know in the comments what resources are missing from our list, and we just may add them to the post!</p></blockquote>]]></content>
  </entry>
</feed>
