<?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:65dfd773-e6e8-49db-a414-6667c0b7dbc2;id=1686</id>
  <updated>2026-07-10T23:42:27Z</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:a18a06d4-7545-4d98-b443-2c8bf61c38c4</id>
    <title type="text">5 Mistakes Teams Make When Scaling  .NET Applications</title>
    <summary type="text">Avoid these common infrastructure-related mistakes when you’re ready to scale your .NET app to keep your performance at scale too.</summary>
    <published>2026-07-10T16:44:45Z</published>
    <updated>2026-07-10T23:42:27Z</updated>
    <author>
      <name>Brien Posey </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/5-mistakes-teams-make-when-scaling-net-applications"/>
    <content type="text"><![CDATA[<p><span class="featured">Avoid these common infrastructure-related mistakes when you&rsquo;re ready to scale your .NET app to keep your performance at scale too.</span></p><p>IT teams often assume that scaling a .NET application means moving it to a larger virtual machine or containerizing the application. While such actions do have their place, performance problems are often tied to infrastructure design rather than the application itself.</p><p>This article discusses some of the most common infrastructure-related mistakes that are often made when scaling a .NET application.</p><h2 id="adding-instances-without-thinking-about-traffic-distribution">1. Adding Instances Without Thinking About Traffic Distribution</h2><p>Application scaling very often involves adding additional nodes to handle the increased demand. However, it is a mistake to add nodes without considering how requests will reach those nodes. Oftentimes organizations will use round-robin load balancing to evenly distribute inbound requests across the available nodes. However, load balancing can break down when session affinity comes into play.</p><p>Session affinity occurs as a result of session data being stored on a specific server. This in turn causes all of a user&rsquo;s requests to be sent to that same server, because that&rsquo;s where the user&rsquo;s session lives. This isn&rsquo;t necessarily a problem by itself, but session affinity can become problematic under the right conditions, especially when there is a mixture of active and inactive users.</p><p>In such situations, a particular instance may become overloaded, even if plenty of capacity exists on other instances, simply because the session is bound to that instance. Additionally, if that instance were to fail, then the users on that instance lose their session.</p><p>A better approach is to design services to be stateless and to store session data within shared storage rather than placing it in an instance&rsquo;s memory. This allows the load balancer to freely distribute requests.</p><h2 id="assuming-that-all-requests-look-alike">2. Assuming That All Requests Look Alike</h2><p>Basic load distribution strategies, such as round robin, assume that every instance can deliver the same level of performance and that every request has the same impact. In reality though, these assumptions are na&iuml;ve.</p><p>Some requests, for example, trigger longer running operations, call external services or make more complex database queries. As such, some requests will inevitably be completed more quickly than others. This can result in some nodes being bogged down while others remain nearly idle.</p><p>The best way to avoid this type of problem is to avoid blindly distributing traffic across nodes. Instead, consider each node&rsquo;s health when making routing decisions. As an example, if a node were experiencing excessive latency or had a significant queue depth, then it would be better to route inbound requests to a node that is under less of a load rather than assigning the request to the struggling node just because it is that node&rsquo;s turn.</p><h2 id="not-having-a-load-shedding-strategy">3. Not Having a Load-Shedding Strategy</h2><p>Although it may seem counterintuitive, load shedding can sometimes be the most appropriate course of action. For those who might not be familiar with the term, load shedding refers to the practice of intentionally rejecting certain requests as a way of helping the system to stay healthy.</p><p>To use an analogy from everyday life, consider what might happen if a restaurant kept seating additional guests in spite of the kitchen and the waitstaff being completely overwhelmed. In such a situation, everyone would receive poor service. Conversely, if the restaurant were to pause and not seat anyone else until the staff had a chance to catch up, then it would result in a better overall experience for everyone.</p><p>Load shedding works similarly. When a system becomes overwhelmed with more requests than the nodes can handle, then the load balancer intentionally fails some requests so that those requests that do make it through can still be serviced normally.</p><h2 id="lack-of-visibility">4. Lack of Visibility</h2><p>This one seems so simple (and it is), yet it is so important. Organizations often make the mistake of just assuming that load balancing is working as intended without doing anything to verify their assumptions. The problem is that if an organization cannot see how requests are being routed, then scaling an application becomes guesswork.</p><p>Without proper visibility, you can&rsquo;t tell whether traffic is being evenly distributed, if there are nodes that are constantly struggling or which instances are handling slow requests. It becomes easy to misdiagnose bottlenecks and blame the application for poor performance when routing is the real problem (or vice versa).</p><p>Ideally, an organization should be able to collect per-instance metrics from its nodes including CPU and memory usage and the request count. There should also be a way to trace requests as they flow across services and there should be a way to track load distribution metrics to see how the individual nodes are being leveraged.</p><h2 id="treating-load-balancing-as-an-afterthought">5. Treating Load Balancing as an Afterthought</h2><p>One of the single biggest mistakes that is often made when scaling an application is treating load balancing as an afterthought. Typically, an application is deployed and works fine. Eventually though, demand increases and the application begins to struggle. IT distributes the application across several nodes and places a basic load balancer in front of those nodes. In these types of situations, load balancers often use default settings because, &ldquo;round robin is good enough for not&rdquo; or &ldquo;the cloud provider&rsquo;s defaults should be fine.&rdquo;</p><p>The end result is that while the application has indeed been scaled, there is a good chance that some of the original problems still exist. The added infrastructure now makes those problems more difficult to diagnose.</p><p>True load balancing is not about spreading traffic evenly. It&rsquo;s about making informed decisions as to where each inbound request should be routed. This informed decision making means using application aware routing to base routing decisions on application behavior, not just routing rules. It also means taking instance health and readiness into account and continually adjusting routing decisions based on latency, errors and available capacity.</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">Using AI to Build a Blazor App 1: Start With the Problem
</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Many AI-assisted projects fail before a line of code is written because the idea was never properly defined. <a target="_blank" href="https://www.telerik.com https://www.telerik.com/blogs/using-ai-build-blazor-app-1-start-problem">Here&rsquo;s how to use an LLM to interrogate your own thinking until a vague premise becomes something you can actually build.</a></p></div></div></aside>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:3ff2a0b3-8691-4d96-86da-ea2ef3472d6f</id>
    <title type="text">When the Time Is Right</title>
    <summary type="text">Priority tells you what matters. Timing tells you if the moment is right. Here’s why that distinction changes everything about how you build.</summary>
    <published>2026-07-09T13:18:49Z</published>
    <updated>2026-07-10T23:42:27Z</updated>
    <author>
      <name>Teon Beijl </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/when-time-right"/>
    <content type="text"><![CDATA[<p><span class="featured">Priority tells you what matters. Timing tells you if the moment is right. Here&rsquo;s why that distinction changes everything about how you build.</span></p><p>A customer threatened to cancel. Full panic. A board meeting to discuss how to retain him, budget approved and allocated to honor his demands. A scrum team started fixing.&nbsp;I flew to the UK to sit with him.</p><p>We had redesigned the entire UI. Not a small fix. We completely overhauled the user experience. From a very old tool with toolbars to an application with a strip.</p><p>We didn&rsquo;t just move buttons to ribbons with tabs. We restructured the entire information architecture. Fixed, opinionated workflows that guided users through the critical steps to model complex geological concepts.</p><p>He hated it. He demanded a rollback.</p><p>I reserved time to interview him. Asked questions. Listened. Tried to sense his reality, his context, where he was coming from. How he was perceiving the changes.</p><p>What I discovered changed everything.</p><p>He wasn&rsquo;t even using the latest version. He hadn&rsquo;t tried the new UI at all. He had simply refused. While we moved on and developed the next generation of our software, he had not. He was still way behind. And somewhere at the back of the queue, feeling ignored and dismissed.</p><p>That feeling made him rage. But it also highlighted a bigger problem.</p><p>In the room next door, two junior geologists were being trained on the exact same concept. They loved it. The design was exactly what the team needed. What he needed too.</p><p>He was desperate for a transformation in his company. A way to step back from his expert role and become a guide for the younger generation. Once I explained the concepts, he understood. He was appreciative of the work. He was on board.</p><p>We almost rolled back an expensive, fundamental shift based on an emotional rant from a customer speaking from expired context.</p><p>It was never about the concept. It was about misunderstanding context.</p><h2 id="the-linearity-trap">The Linearity Trap</h2><p>A backlog is not a queue. It&rsquo;s a context-sensitive collection.</p><p>Every item in it was written at a specific moment, about a specific reality. That reality changes. The backlog doesn&rsquo;t update itself.</p><p>The linearity trap is treating it like a queue anyway. Adding new requests. Reorganizing. Managing delay. Shipping. Without ever asking: does this still belong in the collection?</p><p>The customer had been reporting improvements and bugs for a long time. But we moved on. We shipped. And while we did, he stood still. By the time his feedback reached the top of the queue, the context it was written in had long since changed.</p><p>The problem wasn&rsquo;t that we were behind. We were committing to work that was already outdated.</p><h2 id="delay-is-not-the-problem.-decay-is.">Delay Is Not the Problem. Decay Is.</h2><p>A lot of backlog management is really about managing time. Managing delivery. Focused on shipping as much high-quality work as possible by the promised date.</p><p>Managing delay is a conscious decision. It&rsquo;s about choosing when to push something back. That&rsquo;s prioritization. That&rsquo;s what I wrote about in the previous article.</p><p>But the bigger problem is decay.</p><p>Decay is what happens to the work you&rsquo;re not doing. While you&rsquo;re waiting, while you&rsquo;re delaying, what has been written down is eroding. Rusting. Because context expires.</p><p>It&rsquo;s like the best-before date on a package. By the time you grab it from the shelf, you need to check the date before you consume it.</p><p>A lot of backlogs are just queues constantly filled with requests, feedback and bug reports. Nobody checks the date. Nobody asks: is this still valid?</p><p>I&rsquo;ve seen old backlog items treated as still true when the context they described no longer existed. They were no longer worth pursuing. The more context you capture when you write them, the easier it is to later assess whether they still fit.</p><p>Something can be very old and still be good. But developing the sense to distinguish that is the work. Understanding whether it&rsquo;s expired or not. Whether it&rsquo;s still safe to consume.</p><p>In the UK, the right response would have been to delay any work on his requests. To first discover whether his feedback was based on expired context. Instead, urgency won. And decay nearly cost us everything.</p><h2 id="urgency-vs.-timing">Urgency vs. Timing</h2><p>The urgency that came up was really signaling a demand. Someone pushing. Pressure.</p><p>And under pressure, you don&rsquo;t always make the most strategic decisions. The board panicked. Money appeared. Time was freed up. Nobody stopped to check the return on investment, whether it was worth it. It was an emotional response.</p><p>That happens. We&rsquo;re humans. And that emotion is sometimes also why we close amazing deals and do great things for loyal customers. So it wasn&rsquo;t all wrong. Part of the response was also recognizing the loyalty of a customer who had been with us through harder times.</p><p>But urgency gets the attention. It drives the emotion. And what we need underneath it is judgment.</p><p>Timing is a readiness signal. It&rsquo;s not driven by pressure. It&rsquo;s driven by context.</p><ul><li>Is the customer ready? </li><li>Is the market ready? </li><li>Is the team ready? </li><li>Is the moment alive?</li></ul><p>Those are timing questions. Urgency can&rsquo;t answer them.</p><h2 id="compound-vs.-corrosion">Compound vs. Corrosion</h2><p>We&rsquo;re always looking for momentum. Shipping as much as we can, as fast as possible, without compromising quality.</p><p>But without sensing whether the time is right, we create progress without compounding.</p><p>Compounding is making sure what you ship ties into the next thing and builds over time into the desired version of your software aligned with your vision. Creating conditions so that what comes next makes sense.</p><p>The opposite is corrosion. Work that sits in the backlog long enough starts to corrode. And when you finally act on it, you might ship something that corrodes the foundation of your software rather than building it. Hurting not just momentum but overall quality.</p><p>When we made that big shift to the UI, we should have reassessed the entire backlog. Diagnosed it. Made sure there was no outdated work hiding in the queue because of it.</p><p>We didn&rsquo;t. And a decayed issue almost corroded the core concept.</p><h2 id="context-sensitivity">Context Sensitivity</h2><p>Why did feedback and previous user requests corrode? Because the timeframe wasn&rsquo;t short. That concept developed over multiple months. We should have been capturing the context shift and using it as a filter on our backlog to stay ahead of it.</p><p>But capturing context is the hard part.</p><p>The world moves on. Your market, client and economic reality change constantly. The technical reality shifts the moment you upgrade systems and build with new technologies. The context you&rsquo;re shipping into is constantly moving.</p><p>And on top of that, emotional states. Not everybody handles change well. Not everybody&rsquo;s personal context is aligned with where you&rsquo;re going.</p><p>You need to develop a sense to see those shifts.</p><h2 id="keep-a-human-in-the-loop">Keep a Human in the Loop</h2><p>AI is very good at capturing context. Writing it down. Cross-referencing it. Flagging patterns. It can help us see and track everything we can&rsquo;t manage on our own.</p><p>But the moment context is written down, it&rsquo;s already outdated. And managing that expiration date is a collaborative effort. AI can help cross-check against captured context, flag a customer as a potential churn risk, surface old backlog items that conflict with new ones.</p><p>What it can&rsquo;t do is sit in the room.</p><p>What I did with that customer&mdash;reserving time, asking questions, listening&mdash;that&rsquo;s a nuance. A human sense that becomes more important as we connect more and more data at greater and greater speed.</p><p>AI can read the signal. It can&rsquo;t always hear what&rsquo;s between the lines. The emotional rage that looks like a high-priority request but is really a loyalty problem. The developer who goes quiet in sprint planning. The feedback that reads as a bug report but is actually a cry for better onboarding.</p><p>That&rsquo;s not in the data. It&rsquo;s in the room.</p><h2 id="closure">Closure</h2><p>Timing isn&rsquo;t about managing deadlines. It&rsquo;s about reading whether the moment is right. Priority tells you what matters. Timing tells you whether now is the moment to act on it or not at all.</p><p>The backlog or data alone won&rsquo;t tell you that. You need to read the room. Develop that sense. Check the expiration date. Keep humans in the loop for the context AI can&rsquo;t capture.</p><p>We ship when it matters. We shred when it&rsquo;s expired.</p><p>On purpose. By design.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">How Depending Leads to Independence</h4></div><div class="col-8"><p class="u-fs16 u-mb0"><a target="_blank" href="https://www.telerik.com/blogs/how-depending-leads-independence">True independence isn&rsquo;t the absence of dependencies.</a> It&rsquo;s an intentional integration. An assembly that&rsquo;s clear, chosen and changeable.</p></div></div></aside>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:3688cfa4-c260-412e-918e-9889e5046f2a</id>
    <title type="text">Available Now in .NET 11 for .NET MAUI</title>
    <summary type="text">Explore the .NET 11 updates available now in .NET MAUI, including map enhancements, long press recognition, animation improvements and more.</summary>
    <published>2026-07-08T15:35:21Z</published>
    <updated>2026-07-10T23:42:27Z</updated>
    <author>
      <name>Leomaris Reyes </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/available-now-net-11-net-maui"/>
    <content type="text"><![CDATA[<p><span class="featured">Explore the .NET 11 updates available now in .NET MAUI, including map enhancements, long press recognition, animation improvements and more.</span></p><p>Oh yeahhh!!  .NET 11 for .NET MAUI is here!</p><p>And, as always, my recommendation is to stay up to date with every new release. What changed? What&rsquo;s new? What has been improved? Keeping up with these updates helps us build better apps and keeps our code inline with the latest recommendations from the Microsoft team.</p><p>For .NET 11, the team&rsquo;s main focus has been improving the overall quality of .NET MAUI, making it faster and easier for us as developers, to build amazing applications. In this article, you&rsquo;ll discover some of my favorite improvements that Microsoft has introduced for .NET MAUI in .NET 11!</p><h2 id="maps-improvements">1. Maps Improvements</h2><p>This is one of my favorite updates in .NET 11!  Let&rsquo;s start by exploring the <strong><a target="_blank" href="https://learn.microsoft.com/es-es/dotnet/api/microsoft.maui.controls.maps.map?view=net-maui-10.0">Map</a></strong> control, which has received some really nice improvements. Here are some of the highlights!</p><h3 id="pin-clustering">Pin Clustering</h3><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/01_improvement_map.png?sfvrsn=9f323c91_2" title=".NET MAUI 11 Map Improvement: Pin Clustering" alt="Illustrated maps. Without clustering the pins, they are everywhere. With clustering enabled, blue circles have numbers for how many pins are in that area" /><br /><span style="font-size:11px;">For educational purposes, this image was generated with AI</span></p><p>Imagine you&rsquo;re building a restaurant app where users can view nearby restaurants on a map. You may have <strong>300, 400 or even more locations</strong> to display. If the user opens the map while zoomed out, it could look something like this: </p><p>This quickly becomes overwhelming because many pins overlap, making it difficult to select a specific location.</p><p>With <strong>.NET 11,</strong> you can simply use this property:</p><pre class=" language-xml"><code class="prism  language-xml">IsClusteringEnabled="True"
</code></pre><p>And with that, .NET MAUI will automatically group nearby pins into clusters. So instead of displaying multiple overlapping pins like , users will see something like (5), indicating that five locations are grouped together.</p><p>As users zoom in, those clusters gradually split into individual pins, creating a much cleaner experience and making it much easier to interact with the map.</p><p>Using it in .NET MAUI is incredibly simple:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;maps:Map IsClusteringEnabled="True"

    ClusterClicked="OnClusterClicked" /&gt;
</code></pre><h3 id="custom-location-markers">Custom Location Markers</h3><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/02_improvement_map.png?sfvrsn=74e1d38_2" title=".NET MAUI 11 Map Improvement: Custom Location Markers" alt="Illustrated maps showing custom location markers for hospitals and pharmacies, instead of the simple pin" /><br /><span style="font-size:11px;">For educational purposes, this image was generated with AI</span></p><p>Yay!!  Another great addition is the ability to <strong>customize your map markers</strong>.</p><p>Instead of using the default pin for every location, you can now display a custom image for each marker, making your maps much more intuitive and visually appealing.</p><p>For example, imagine you&rsquo;re building a healthcare app. You could use one icon for <strong>hospitals</strong> and a different one for <strong>pharmacies</strong>, allowing users to quickly identify each type of location without even reading the labels.</p><p>This is possible by simply setting the <strong>ImageSource</strong> property on the pin.</p><p>Here&rsquo;s what it looks like in code:</p><pre class=" language-csharp"><code class="prism  language-csharp">var pin = new Pin
{ 
    Label = "Custom pin", 
    Location = new Location(18.4861, -69.9312), 
    ImageSource = ImageSource.FromFile("hospitals.png") 
};
</code></pre><h3 id="json-map-style-android">JSON Map Style (Android)</h3><p>Google Maps allows you to customize the map using a JSON file. This means you can change colors, switch between light and dark mode, customize labels and much more.</p><p>Previously, this was much more complicated in .NET MAUI. Now, all you have to do is assign your JSON file to the <strong>MapStyle</strong> property, and you&rsquo;re done! </p><h2 id="cancel-animations-with-cancellationtoken">2. Cancel Animations with CancellationToken</h2><p>This improvement may seem small, but it&rsquo;s actually a very useful one, especially when you have multiple animations running at the same time.</p><p>Before .NET 11, if you started an animation and later wanted to stop it, your only option was to do something like this:</p><pre class=" language-csharp"><code class="prism  language-csharp">image.CancelAnimations();
</code></pre><p>However, there was a small problem.  This method <strong>canceled every animation</strong> running on that control.</p><p>Imagine your image is running two animations simultaneously: a rotation animation and a fade animation. If you only wanted to stop the rotation while keeping the fade animation running, that simply wasn&rsquo;t possible.</p><p>Starting with .NET 11, the animation methods now optionally accept a <strong>CancellationToken</strong>. This means you can cancel a specific animation without affecting the others.</p><p>For example:</p><pre class=" language-csharp"><code class="prism  language-csharp">var cts = new CancellationTokenSource();

await image.FadeToAsync( 
opacity: 0, 
cancellationToken: cts.Token);
</code></pre><p>And when you want to stop that animation:</p><pre class=" language-csharp"><code class="prism  language-csharp">cts.Cancel();
</code></pre><p>That&rsquo;s it! Only the animation associated with that <strong>CancellationToken</strong> will be canceled, while any other animations on the same control will continue running normally.</p><h3 id="methods-without-async-are-now-obsolete">Methods Without Async Are Now Obsolete</h3><p>Another important change is that animation methods without the <strong>Async</strong> suffix have now been marked as obsolete. Methods such as <strong>FadeTo(), RotateTo() and ScaleTo()</strong> are now marked as <strong>[Obsolete].</strong> Instead, Microsoft recommends using their asynchronous counterparts:</p><ul><li>await FadeToAsync(&hellip;);</li><li>await RotateToAsync(&hellip;);</li><li>await ScaleToAsync(&hellip;);</li></ul><p>Of course, these methods also support the new <strong>CancellationToken</strong>, giving you much greater control over your animations.</p><h2 id="longpressgesturerecognizer">3. LongPressGestureRecognizer</h2><p>Have you noticed that some actions in mobile apps are only triggered when you press and hold a control for some seconds? Thanks to <strong>.NET 11</strong>, .NET MAUI now includes the <strong>LongPressGestureRecognizer</strong>, making it easy to detect this gesture.</p><p>It provides several useful features:</p><ul><li>Detects long-press gestures</li><li>Configurable press duration</li><li>Movement threshold to cancel the gesture if the finger moves too far</li><li>Gesture state tracking through GestureState</li><li>Support for Command and CommandParameter</li></ul><p>Using it is as simple as this:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Image Source="flower.png"&gt; 
&lt;Image.GestureRecognizers&gt; 
&lt;LongPressGestureRecognizer 
    Duration="500" 
    LongPressed="OnLongPressed"/&gt; 
    &lt;/Image.GestureRecognizers&gt; 
&lt;/Image&gt;
</code></pre><p>The event:</p><pre class=" language-csharp"><code class="prism  language-csharp">void OnLongPressed(object sender, LongPressGestureRecognizerEventArgs e) 
{ 
    if (e.State == GestureState.Completed) 
    { 
    // Your code goes here 
    } 
}
</code></pre><h2 id="we-can-finally-use-gradients-in-boxview">4. We Can Finally Use Gradients in BoxView!</h2><p>BoxView is a super useful control that gives us a lot of flexibility when building UI. However, before .NET 11, it had one important limitation: <strong>it could only display a solid color.</strong> So, if you wanted a gradient, you had to rely on other controls or custom solutions.</p><p>With .NET 11, BoxView now includes the Fill property, which is of type Brush. This means you can finally apply gradients directly to a BoxView! And don&rsquo;t worry, if you only need a solid color, you can continue using the BackgroundColor property as before.</p><p>Here&rsquo;s a simple example:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;BoxView HeightRequest="260"&gt; 
    &lt;BoxView.Fill&gt; 
    &lt;LinearGradientBrush&gt; 
    ... 
    &lt;/LinearGradientBrush&gt; 
    &lt;/BoxView.Fill&gt; 
&lt;/BoxView&gt;
</code></pre><h2 id="trimmable-css">5. Trimmable CSS</h2><p>I don&rsquo;t know if you knew this, but .NET MAUI has supported CSS for quite some time. The problem was that even if your application didn&rsquo;t use CSS, .NET MAUI still had to include all the infrastructure required to support it, increasing the final size of your app.</p><p>With .NET 11, that&rsquo;s no longer the case. If your application doesn&rsquo;t use CSS stylesheets, the CSS infrastructure is automatically removed during the publishing process. In short, if you don&rsquo;t use CSS, your application becomes smaller <strong>without you having to do anything</strong>.</p><h2 id="material-3-on-android">6. Material 3 on Android</h2><p>Previously, some .NET MAUI controls on Android were not fully aligned with Material 3. Starting with .NET 11 Preview 4, several Android handlers now use <strong>Material 3</strong> by default. This applies to controls such as:</p><ul><li>ImageButton</li><li>DatePicker</li><li>Entry</li><li>Slider</li></ul><p>In short, it was common to find controls that didn&rsquo;t fully follow Android&rsquo;s modern design guidelines. With .NET 11, that changes. These controls are now much more aligned with Material 3, resulting in a more modern, consistent look that feels fully integrated with the Android ecosystem. </p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/03_improvement_material_controls.png?sfvrsn=9620bef2_2" title=".NET MAUI 11 Material 3 on Android" alt="Material 3 on Android in dark and light mode on .NET MAUI now in >NET 11" /><br /><span style="font-size:11px;">Image obtained from the official documentation</span></p><h2 id="conclusion">Conclusion</h2><p>And that&rsquo;s it! I hope this article helps you discover some of the exciting new features coming to .NET MAUI with .NET 11.</p><p>Throughout this article, we explored some of my favorite improvements, including the new LongPressGestureRecognizer, Map enhancements, BoxView gradients, animation improvements and Android Material 3 support.</p><p>Of course, these are just a few of my favorites! I encourage you to explore the article &ldquo;<a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/maui/whats-new/dotnet-11?view=net-maui-10.0">What&rsquo;s new in .NET MAUI for .NET 11</a>&rdquo; from the official documentation to discover even more improvements and enhancements included in this release.</p><p>I also encourage you to keep experimenting with these new features and continue learning something new every day. </p><p>See you in the next article! &zwj;♀️</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">What&rsquo;s New for Blazor in .NET 11 Preview Releases 1 and 2</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Tour the <a target="_blank" href="https://www.telerik.com/blogs/whats-new-blazor-net-11-preview-releases-1-2">notable Blazor changes and new features in .NET 11 Previews 1 and 2</a> for an early glimpse into what&rsquo;s coming for Blazor in .NET 11.</p></div></div></aside>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:082495fa-3b2a-46e9-b13f-1d4ee4d3a2a9</id>
    <title type="text">The Importance of Empathy in Automation</title>
    <summary type="text">To take AI beyond automation into true intelligence, we need to include empathy.</summary>
    <published>2026-07-08T13:10:10Z</published>
    <updated>2026-07-10T23:42:27Z</updated>
    <author>
      <name>Jefferson S. Motta </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/importance-empathy-automation"/>
    <content type="text"><![CDATA[<p><span class="featured">To take AI beyond automation into true intelligence, we need to include empathy.</span></p><p>In this post, I want to discuss a real danger we may face with AI agents, drawn from a specific interaction I witnessed on LinkedIn.</p><p>Recently, on a post where someone was presenting ideas about &ldquo;intelligent&rdquo; AI agents, the author claimed that if a customer fails to pay a SaaS subscription, the system will block access, trigger an automatic charge and apply a late fee, all without any human intervention. This was promoted as something futuristic and advanced.</p><p>I saw a disaster waiting to happen, especially considering that the same outcome could be achieved without AI, if that were ever desirable.</p><h2 id="what-was-not-considered-the-human-element">What Was Not Considered: The Human Element</h2><p>There are many situations that can lead to a missed payment. What happens, for example, if the client&rsquo;s assistant falls ill and cannot process the payment? What if they had a medical emergency and no one took over the task in time? What if the invoice never arrived? What if the client is going through a temporary hardship, but has been a loyal customer for years? Does that count for nothing? Where is the human element in the consumer relationship?</p><p>These are not far-fetched hypotheticals. They have happened with my own SaaS customers.</p><blockquote><p><strong><em>Automation without humanity is oppression at scale.</em></strong></p></blockquote><p>We could easily implement the AI agent&rsquo;s suggestion and follow the same path: missed payment, blocked account and a fine applied. But is this the right approach?</p><p>My background in neuroscience and communication reshaped how I think about the human side of technology-driven processes. That plus some life experiences lead me to consider the broader context:</p><ul><li>In many jurisdictions, consumer protection laws prohibit unilateral penalties without proper notice. Implementing such a drastic automatic response could have legal implications.</li><li>In society, there is the principle of good faith. Every commercial relationship presumes that both parties act honestly until proven otherwise. This action could have serious consequences for that business relationship and reputation.</li><li>We have to remember to consider the human context. Behind every business and every overdue charge, there are people with stories, setbacks and circumstances that must be considered before any penalty is applied.</li></ul><h2 id="what-we-should-actually-build">What We Should Actually Build</h2><p>A genuinely intelligent AI agent does not block first and ask questions later. It recognizes patterns. Has this client always paid on time? Then the delay probably has a reason. The system could send an empathetic notification before taking any action. It could offer a courtesy window. It could escalate the issue to a human when the situation is ambiguous. An intelligent agent could prioritize retaining a client, which is often worth far more than punishing a late payment.</p><p>For those building AI agents: <strong>before you automate punishment, automate empathy</strong>. Your system will reflect your values. If you build without considering the person on the other side, you could be constructing a scalable injustice machine, one capable of generating damages that could exceed any original problem the AI was trying to address.</p><blockquote><p><strong><em>Technology without empathy is not innovation. It is regression with a polished interface.</em></strong></p></blockquote><h2 id="conclusion">Conclusion</h2><p>We are at a moment where the architecture and design decisions we make today will shape how millions of people are treated by systems over which they have no control.</p><p>And to help avoid building oppressive and unjust machines, we need to cultivate empathy and uphold our organizations&rsquo; principles, with the greater purpose of <strong>serving people</strong> rather than merely extracting value from them.</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">AI Can&rsquo;t Solve It All: What Frontend Devs Still Hate Working On</h4></div><div class="col-8"><p class="u-fs16 u-mb0">What still causes the most friction when building modern web applications? <a target="_blank" href="https://www.telerik.com/blogs/ai-cant-solve-all-what-120-frontend-developers-say-they-still-hate-working">120+ developers at JSNation and React Summit weigh in.</a></p></div></div></aside>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:8720cf41-2dac-4533-a2fe-cf1af00e248f</id>
    <title type="text">Using AI to Build a Blazor App 1: Start With the Problem</title>
    <summary type="text">Many AI-assisted projects fail before a line of code is written because the idea was never properly defined. Here’s how to use an LLM to interrogate your own thinking until a vague premise becomes something you can actually build.</summary>
    <published>2026-07-07T15:05:27Z</published>
    <updated>2026-07-10T23:42:27Z</updated>
    <author>
      <name>Jon Hilton </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/using-ai-build-blazor-app-1-start-problem"/>
    <content type="text"><![CDATA[<p><span class="featured">Many AI-assisted projects fail before a line of code is written because the idea was never properly defined. Here&rsquo;s how to use an LLM to interrogate your own thinking until a vague premise becomes something you can actually build.</span></p><p>How do you go from idea to working software? That&rsquo;s the challenge we face as software developers.</p><p>While AI <strong>feels</strong> like it&rsquo;s changed everything, it hasn&rsquo;t changed that fundamental problem.</p><p>It&rsquo;s not a question of how quickly AI can write code (answer: very quickly), but rather how soon can we find out if our assumptions are correct and if we&rsquo;re building the right thing to move the needle.</p><p>Do we even know what needle we&rsquo;re trying to move in the first place?</p><p>In this short series, we&rsquo;ll explore how we can use AI to build the right things, to solve the most urgent problems, without shipping substandard code.</p><ul><li>We&rsquo;ll start with a vague premise and see if AI can help us sharpen our understanding of what we&rsquo;re building (and why).</li><li>Then we&rsquo;ll move on to working with AI to carve out the headline feature we want to build first.</li><li>We&rsquo;ll remove ambiguity (and reach a shared understanding of what we&rsquo;re building) using prototypes and tracer bullets.</li><li>Then we&rsquo;ll establish the architecture of what we&rsquo;re building (including key technology choices), break the work down into smaller steps and build it.</li></ul><p>First, we need to get clear about what we&rsquo;re building.</p><h2 id="a-journey-of-a-thousand-miles-begins-with-a-single-step">A Journey of a Thousand Miles Begins with a Single Step</h2><p>If you&rsquo;ve been experimenting with AI, you already know the big AI trap. The temptation to just throw a vague prompt its way, cross your fingers and hope it magically builds the perfect web application (while you sleep).</p><p>In reality it&rsquo;s not that simple.</p><p>AI will happily run off and build whatever you ask it to, which is problematic if you ask it to build the wrong thing, start with fuzzy requirements or give it too much to do in one step.</p><p>So, the first task is the same as it&rsquo;s always been: get clear about the problem you&rsquo;re solving.</p><p>In this case, I started with a simple problem to solve. I have a goal of writing at least one article a week for my personal blog and also an email to my newsletter audience (based on the same blog post). In reality, that cadence is rarely once a week, and often drifts to once a month or, in the worst case, once &ldquo;every now and then.&rdquo;</p><p>So starting with that problem, I gave this prompt to GPT 5.5 (via the Codex GUI):</p><blockquote><p>I want to build a new web application using .NET 10 and Blazor. Please grill me on the idea, what it&rsquo;s for, key technology choices, and help me scope out a reasonable first version so we can get user feedback as soon as possible</p></blockquote><p>This did <strong>not</strong> go well.</p><p>GPT 5.5 responded with a giant wall of text and lots of questions. It started diving into implementation details about Blazor (which render mode to use, etc.) and essentially skipped the part where it finds out what I&rsquo;m trying to build before focusing on those implementation details.</p><p>I started over, and tried different variations of the same prompt.</p><p>First I got it to ask me one question at a time, which worked better, but I realized it was still jumping to technical details. I wanted to keep it focused on problems and ideal outcomes, not technical matters or even defining the feature details at this stage.</p><p>After a few iterations we arrived at this:</p><blockquote><p>I want to build a new web application using .NET 10 and Blazor.</p><p>Please grill me on the idea.</p><p>Ask me one question at a time, and include your brief recommendation for each question.</p><p>Dig into each answer until that thread is clear, then move on to the next question.</p><p>For notable decisions (anything fundamental, or where the reasoning for which can&rsquo;t be deduced from implementation), capture that decision as an ADR in a decisions folder.</p><p>Help me explore the problem space, and the core outcomes we want this application to achieve.</p><p>Do not scope features at this point, that will come next.</p></blockquote><p>This worked better.</p><p>Over the course of a 45-minute back-and-forth, we fleshed out the problem I was trying to solve, and the rough shape of any potential solution. I won&rsquo;t include the entire conversation here, but here are some highlights.</p><p>It asked:</p><blockquote><p>Where do ideas currently appear first: while at your computer, on your phone, in notes, in code/projects, from conversations, or somewhere else?</p></blockquote><p>The answer I gave included this phrase: &ldquo;Could be anywhere really.&rdquo;</p><p>GPT 5.5 wasn&rsquo;t having that.</p><blockquote><p>This one isn&rsquo;t quite a decision yet, because &ldquo;could be anywhere&rdquo; can lead to a lot of product surface.</p><p>Follow-up question:</p><p>For the first version, is it acceptable if mobile capture is only a lightweight inbox, with real writing/editing still expected to happen at a keyboard?</p></blockquote><p>In my experience, AI shines with this kind of process, digging into answers you give it and getting clear so you can make concrete decisions, not just hand-wavey &ldquo;ideas.&rdquo;</p><p>Some more questions it posed:</p><blockquote><p>What would make this application feel like a calm writing system rather than another obligation to maintain?</p></blockquote><blockquote><p>What is the smallest publishing rhythm that would still feel successful: exactly one post/email every week, or a sustainable average with occasional skips and catch-ups?</p></blockquote><blockquote><p>What would make you stop using this app, even if it technically worked?</p></blockquote><p>Notice how GPT 5.5 stayed on task here, exploring the problem and not getting into feature design, or technical choices.</p><p>Eventually we arrived at this summary:</p><blockquote><p>The core shape is now clear: a local-first, single-user Blazor/.NET app that helps you maintain a weekly blog-plus-newsletter rhythm, with the Astro repo as source of truth, a calm Markdown writing experience, lightweight AI assistance, and explicit publishing/Git steps.</p></blockquote><p>The main technical decision made was the one I started with (that we&rsquo;d be using Blazor to build it) and some high level thoughts around source of truth, and the existing systems (like my blog).</p><p>We also ended up with a number of architecture decision records (ADRs) captured in markdown documents. ADRs are typically used to capture technical decisions, but were also useful here for capturing the decisions we arrived at around the problem and solution itself.</p><p>Here&rsquo;s one example:</p><pre class=" language-markdown"><code class="prism  language-markdown"><span class="token title important"><span class="token punctuation">#</span> ADR 0028: Slug Generation</span>
Status
Accepted

<span class="token title important"><span class="token punctuation">##</span> Context</span>
Blog posts need a final URL slug. The slug should usually be short, readable, and aligned with the article's content or main takeaway.

Manual override is sometimes needed.

<span class="token title important"><span class="token punctuation">##</span> Decision</span>
The application should generate slugs automatically from the article title or main takeaway, while allowing the user to override them.

Slugs should be treated as stable after publication unless deliberately changed.

<span class="token title important"><span class="token punctuation">##</span> Consequences</span>
Slug generation should optimize for short, meaningful URLs rather than blindly mirroring the full title.
The user must retain control over the final slug.
Published slug changes should be treated as deliberate edits, not incidental metadata updates.
</code></pre><p>Whenever I work through an AI interview like this, I find I emerge with a much clearer picture of what I&rsquo;m building (and why). The LLM&rsquo;s questions force me to think and often surface angles I hadn&rsquo;t previously considered. In some cases I&rsquo;ve gone on to realize building a feature is actually unnecessary (a change to existing habits or processes would achieve the same result).</p><p>In this case, though, we&rsquo;re on the right track and have a clearly scoped brief for an editor to capture ideas and author content.</p><h2 id="make-it-work-for-you">Make It Work for You</h2><p>When you try to use AI to build something like this, you might feel like there should be some simple streamlined process you can work through. A clean process where you feed a feature idea in, AI gives you perfect code out and you ride off into the sunset.</p><p>Alas, software design is anything but streamlined, and no AI tool is going to take the chaos of defining and refining an idea and handle it in a nice straight line.</p><p>In this case, getting AI to grill you about the idea is one part of the design process, but there are others, which we&rsquo;ll come to shortly. We started high-level here because this was an embryonic idea and a greenfield application. But if you already had an app and were adding a feature, you might skip this step and jump straight into designing a specific feature/requirement.</p><h2 id="iterate-your-prompts">Iterate Your Prompts</h2><p>But what about the prompt itself? Did I happen upon some perfect, fully formed prompt that made AI work perfectly? In short, no!</p><p>Prompts rarely arrive fully formed. In this case, I started with a vague prompt, then refined and tested it until I found one that worked better for my needs. This is a key difference I&rsquo;ve noticed between people who get good results from an LLM and those who feel frustrated.</p><p>It&rsquo;s useful to learn how to write effective prompts, or &ldquo;meta prompts&rdquo; (where you get AI to write the prompt for you), and run rapid iterations so you can get something that works for you. Here it took around five minutes to get to a prompt that worked well for this exercise.</p><p>You can also turn to examples published online (Matt Pocock&rsquo;s skills are a clear standout), but it&rsquo;s useful to learn how to create your own skills/prompts, based on your own unique workflow and preferences.</p><p>With that said, we&rsquo;ve carved out our idea: a simple &ldquo;surface&rdquo; for capturing ideas and turning those into articles (with the source of truth being an MDX in an Astro blog).</p><p>Now to define the headline features. That&rsquo;s next, in Part 2.</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">AI Can&rsquo;t Solve It All: What Frontend Devs Still Hate Working On</h4></div><div class="col-8"><p class="u-fs16 u-mb0">What still causes the most friction when building modern web applications? <a target="_blank" href="https://www.telerik.com/blogs/ai-cant-solve-all-what-120-frontend-developers-say-they-still-hate-working">120+ developers at JSNation and React Summit weigh in.</a></p></div></div></aside>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:23c4afbf-be58-4e27-8443-2bfe893aab86</id>
    <title type="text">Getting Started with Angular Signal Forms</title>
    <summary type="text">Learn the basics of Angular Signal Forms, including models, validation and two-way synchronization, to build reactive forms with confidence.</summary>
    <published>2026-07-07T12:13:54Z</published>
    <updated>2026-07-10T23:42:27Z</updated>
    <author>
      <name>Dhananjay Kumar </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/getting-started-angular-signal-forms"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn the basics of Angular Signal Forms, including models, validation and two-way synchronization, to build reactive forms with confidence.</span></p><p>Angular version 21.0 introduced one of the most exciting and awaited features: Signal Forms. Traditionally, there have been two types of forms:</p><ol><li>Template Forms</li><li>Reactive Forms</li></ol><p>Angular 21.0 introduced a new form type:</p><ol start="3"><li>Signal Forms</li></ol><p>And now,&nbsp;<a href="https://www.telerik.com/blogs/angular-22-evolution-modern-angular" target="_blank">Angular 22</a> makes Signal Forms stable.&nbsp;Signal Forms are a combination of Signal-based reactivity and forms. In my opinion, Signal Forms are the future of forms and user input in Angular.</p><p>This article gives you a basic introduction to Signal Forms and shows you how to work with models, validation and two-way synchronization.</p><h2 id="first-signal-form">First Signal Form</h2><p>Signal-based forms use a new form function. It creates a form from a writable signal model, where the model is the source of truth, and any change in the form or the model is automatically reflected in the other.</p><p>Let&rsquo;s start by creating an interface to represent the user:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IUser</span> <span class="token punctuation">{</span>
    email<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
    password<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Next, we create a model that will be used to create the form, as shown below. As mentioned earlier, the model must be a writable signal.</p><pre class=" language-ts"><code class="prism  language-ts">user <span class="token punctuation">:</span> WritableSignal<span class="token operator">&lt;</span>IUser<span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    email<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    password<span class="token punctuation">:</span> <span class="token string">''</span>  
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre><p>We can create a signal-based form using the <code>form()</code> function from the <code>@angular/forms/signals</code>.</p><pre class=" language-ts"><code class="prism  language-ts">loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>That&rsquo;s it. You have created a signal-based form in Angular.</p><p>The form function returns a <code>FieldTree</code>, where each field is represented as a signal. In other words, the form function produces a data structure in which every field is a signal enriched with signal-based properties such as value, dirty, invalid and others.</p><p>To better understand this structure, let&rsquo;s print the following values:</p><pre class=" language-ts"><code class="prism  language-ts">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">loginForm</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">valid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">invalid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">dirty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">touched</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">errors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>As shown in the example above, the email field is a signal, and all of its properties are signals as well. Because both the field and its properties are signals, you can use them directly in the template, as demonstrated below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.email<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.password<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
</code></pre><p>To use <code>formField</code>, import it into the component class, as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> form<span class="token punctuation">,</span> FormField <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/forms/signals'</span><span class="token punctuation">;</span>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


  loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">,</span> <span class="token punctuation">(</span>schema<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">email</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is not valid'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>password<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'password is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>As shown above, you provide a schema definition along with validation rules to apply validations to the respective fields of the form.</p><p>The schema function gets a <code>SchemaPathTree</code> object that lets us define the validation rules. The schema function runs at the time of initialization, and validation runs automatically whenever field values change.</p><p>On the template, you can use the validation as shown below:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
        Email
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.email<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
    @if (loginForm.email().invalid() &amp;&amp; loginForm.email().touched()) {
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>error<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        @for (error of loginForm.email().errors(); track error.kind) {
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>{{ error.message }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        }
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    }
</code></pre><p>Validation works in these steps:</p><ol><li>Define validation rules in schema</li><li>Validation rules runs when filed value changes</li><li>Validation errors are propagated as signals</li><li>UI automatically updates when validation state changes</li></ol><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/define-validation-rules-flow.png?sfvrsn=d710c039_2" alt="Define validation rules. Automatic execution of validation rules. Validation error propagates as Signals. Reactive update of UI on validation state changes" /></p><p>There are two types of validations:</p><ol><li>Synchronous validation &ndash; <code>required()</code>, <code>email()</code>, etc.</li><li>Asynchronous validation &ndash; <code>validateHttp()</code></li></ol><p>When a field value changes, Angular runs validation in the sequence:</p><ol><li>First it runs all synchronous validations.</li><li>If all synchronous validation pass, then it runs asynchronous validation.</li><li>After that, it updates the field state signal values such as <code>valid()</code>, <code>invalid()</code>, <code>errors()</code> and <code>pending()</code>.</li></ol><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/sync-validations-flow.png?sfvrsn=d7f77ce4_2" alt="Flow chart. Run synchronous validations. Passed – no or Run async validation. Update field state." /></p><p>Angular provides these built-in validation rules:</p><ol><li><code>required()</code></li><li><code>email()</code></li><li><code>min()</code></li><li><code>max()</code></li><li><code>minLength()</code></li><li><code>maxLength()</code></li><li><code>pattern()</code></li></ol><p>You can apply <code>required()</code> and <code>email()</code> validation on email field as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">  loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">,</span> <span class="token punctuation">(</span>schema<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">email</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is not valid'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>When you have multiple validation rules applied, each rule runs independently and can cause form to be invalid.</p><p>Angular Signal Forms make it straightforward to implement custom validations. For example, if you want to verify that the email belongs to the nomadcoder domain, you can easily add a custom validator as shown below.</p><pre class=" language-ts"><code class="prism  language-ts">  loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">,</span> <span class="token punctuation">(</span>schema<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">email</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is not valid'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token function">validate</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> value <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">endsWith</span><span class="token punctuation">(</span><span class="token string">'@nomadcoder.ai'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token punctuation">{</span>
          kind<span class="token punctuation">:</span> <span class="token string">'emailDomain'</span><span class="token punctuation">,</span>
          message<span class="token punctuation">:</span> <span class="token string">'Email must end with @nomadcoder.ai'</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In upcoming articles, we will get into details of custom validation and asynchronous validation.</p><h2 id="form-field-and-its-signal-properties">Form Field and Its Signal Properties</h2><p>The <code>form</code> function returns a <code>FieldTree</code> that represents all properties of the model. Each property is exposed as a signal, and each property signal includes a set of attributes that are also implemented as signals.</p><p>When you access a field from the field tree, as shown below, you can retrieve its associated attributes as illustrated:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/field-tree-attributes.png?sfvrsn=d73e4df6_2" alt="After  the next line has  and a list of attributes comes up" /></p><p>The various signal attributes are as below:</p><ol><li><code>value()</code></li><li><code>dirty()</code></li><li><code>hidden()</code></li><li><code>errors</code></li><li><code>errorSummary</code></li><li><code>valid</code></li><li><code>invalid</code></li><li><code>pending</code></li><li><code>submitting</code></li><li>Etc.</li></ol><p>As all these are <code>signals()</code>, they can be directly used on the template. I hope now you understand Angular Signal Forms. In coming articles, we will go deeper into:</p><ol><li>asynchronous validators</li><li>custom validators</li></ol><p>I hope you find this article useful. Thanks for reading.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Angular Signals: Building a Reactive Countdown Timer</h4></div><div class="col-8"><p class="u-fs16 u-mb0">A comprehensive tutorial for experienced Angular developers to learn <a target="_blank" href="https://www.telerik.com/blogs/angular-signals-building-reactive-countdown-timer">Angular Signals by building a practical countdown timer</a> application with computed signals and effects.</p></div></div></aside>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:c92d89d9-25b7-41e4-bb56-1df47761789e</id>
    <title type="text">AI Can’t Solve It All: Here’s What 120+ Frontend Developers Say They Still Hate Working On</title>
    <summary type="text">What still causes the most friction when building modern web applications? 120+ developers at JSNation and React Summit weigh in.</summary>
    <published>2026-07-06T14:05:08Z</published>
    <updated>2026-07-10T23:42:27Z</updated>
    <author>
      <name>Kathryn Grayson Nanz </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/ai-cant-solve-all-what-120-frontend-developers-say-they-still-hate-working"/>
    <content type="text"><![CDATA[<p><span class="featured">What still causes the most friction when building modern web applications? 120+ developers at JSNation and React Summit weigh in.</span></p><p>While we were at JSNation and React Summit (<a href="https://www.telerik.com/blogs/check-out-amazing-projects-progress-gitnation-hackathon" target="_blank">read about our hackathon there</a>!), we wanted to take advantage of our booth space to do a little user research. We asked folks who stopped by to answer a simple question for us: <strong>What still causes the most friction when building modern web applications?</strong></p><p>Instead of running a formal survey, we set up a whiteboard, handed folks a sticky note and a sharpie, and invited them to air their grievances. Over the two days of the combined conferences, we collected 120+ responses across two prompts:</p><ul><li><strong>Day 1 (JS Nation):</strong> <em>What&rsquo;s the most annoying frontend task or component to build from scratch?</em></li><li><strong>Day 2 (React Summit):</strong> <em>What does AI still get wrong when building UI in React?</em></li></ul><p><img sf-image-responsive="true" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/.net-maui-aiprompt/1781254429274.jpg?sfvrsn=45fc2fa8_2" /></p><p>The responses were (at least to me) surprisingly consistent. While frameworks, tooling and AI assistants continue to evolve, many of the age-old pain points haven&rsquo;t disappeared. Turns out, it sucked to build a date picker 10 years ago and it still sucks today. </p><h2 id="building-ui-components-is-still-a-challenge">Building UI Components Is Still a Challenge</h2><p>We left the first question open-ended, allowing folks to pick between tasks and components that they found annoying. Personally, I was expecting to see more tasks than components&mdash;especially now that we can AI-generate components fairly quickly&mdash;but that&rsquo;s not what happened. In fact, the split between individual components and tasks was a fairly even split. </p><p><strong>Date picker components</strong> topped the list, with developers calling out everything from timezone handling to accessibility and date ranges. Unsurprisingly, <strong>AI</strong> is next up&mdash;adopting any new technology is going to come with some pain points and process adjustments. <strong>Accessibility</strong> was in third place with several callouts about struggling with compliance and testing, specifically. </p><table><style>table,
 th,
    td {
      border: 1px;
      border-color: #bdbdba;
      border-style: dotted;
      border-collapse: collapse;
      padding: 0in 5.4pt 0in 5.4pt;
    }
  </style>
 <thead><tr><th>Theme</th><th>Mentions</th></tr></thead><tbody><tr><td>Date pickers</td><td>9</td></tr><tr><td>AI-related work (including prompt engineering, dealing with AI-generated designs, AI features in components, skill writing and chatbot components)</td><td>8</td></tr><tr><td>Accessibility (including WCAG compliance, testing and mentions of specific challenging components such as calendars and comboboxes)</td><td>7</td></tr><tr><td>Requirements &amp; development process (including scope creep, non-technical coworkers, client management)</td><td>6</td></tr><tr><td>Data grids &amp; tables</td><td>5</td></tr><tr><td>Rich text editors</td><td>4</td></tr><tr><td>Design systems &amp; theming</td><td>4</td></tr><tr><td>Comboboxes</td><td>4</td></tr></tbody></table><br /><h2 id="ai-has-become-part-of-the-workflow-and-part-of-the-friction">AI Has Become Part of the Workflow&mdash;and Part of the Friction</h2><p>As you can see in the results above, even before we introduced an AI-specific discussion on Day 2 developers were already talking about AI. But when we asked specifically about AI-generated React code, the conversation shifted from whether AI is useful to where it still struggles<em>.</em></p><table><thead><tr><th>Theme</th><th>Mentions</th></tr></thead><tbody><tr><td>React architecture</td><td>6</td></tr><tr><td>CSS &amp; styling</td><td>4</td></tr><tr><td>Effects &amp; async logic</td><td>2</td></tr><tr><td>Animation</td><td>2</td></tr></tbody></table><br /><p>The top complaint was related to React architecture. Developers repeatedly mentioned AI-generated code that:</p><ul><li>Violates the rules of hooks</li><li>Creates unnecessary <code>useState</code> calls</li><li>Places state outside components</li><li>Generates new components instead of reusing existing ones</li><li>Produces code without understanding project requirements</li><li>Includes poor quality CSS</li></ul><h2 id="some-pain-points-refuse-to-go-away">Some Pain Points Refuse to Go Away</h2><p>Across both days, several themes kept resurfacing. Accessibility appeared on both walls, suggesting that AI hasn&rsquo;t eliminated many of the challenges developers face when building inclusive interfaces. Developers also repeatedly mentioned:</p><ul><li>Design systems</li><li>Figma-to-code workflows</li><li>Localization</li><li>Testing</li><li>State management</li><li>Performance</li><li>CSS</li></ul><p>These aren&rsquo;t new problems&mdash;and many of them have to do with very human aspects of software development such as coordination across teams, inclusivity, creating work for a global audience and user testing.</p><p><img sf-image-responsive="true" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/.net-maui-aiprompt/screenshot-2026-06-30-at-2-00-50-pm.png?sfvrsn=c0402f64_2" height="700" style="max-width:100%;height:auto;" title="Screenshot 2026-06-30 at 2.00.50 PM" width="728" alt="" sf-size="942727" /></p><h2 id="so-what-does-all-this-mean">So? What Does All This Mean</h2><p>The difficulty now (as it always has been) is in the integration of tools into cohesive systems. The tools have changed, but the challenge has not. Frontend developers today are spending their time wrestling with accessibility, architecture, complex UI components, evolving requirements and figuring out how to integrate AI into real production workflows.</p><p>AI is clearly changing how developers build software, but it hasn&rsquo;t eliminated the need for thoughtful engineering. In many cases, it&rsquo;s shifted developers&rsquo; attention toward reviewing, refining and improving generated code rather than writing every line themselves. Whether that&rsquo;s an improvement or not is something only time will tell. </p><p>The good news is that many of the component-centric frustrations that developers shared at our booth&mdash;date pickers, data grids, accessibility, design systems and more&mdash;all have something in common: they&rsquo;re problems with existing solutions.</p><p>Modern component libraries exist so developers can focus on building the unique parts of their applications instead of spending weeks recreating foundational UI. Likewise, AI tools are most effective when paired with production-ready building blocks that help developers generate better code, faster. </p><p>Investing in the right UI foundation can remove much of the friction developers told us they&rsquo;re still experiencing today. We may not have the answer to <em>every</em> frontend development struggle, but there are plenty that the <a href="https://www.telerik.com/home.aspx" target="_blank">Progress Telerik and Kendo UI</a> libraries can help address today.</p>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:c7659abf-70b7-4ba4-a7d1-5ece28dc3d4a</id>
    <title type="text">A Developer’s Guide to State Management with Effector</title>
    <summary type="text">Learn to build a simple app that shows how Effector handles state, async operations and UI updates. The app will allow users add, update, delete and load todos from an API.</summary>
    <published>2026-07-06T12:53:56Z</published>
    <updated>2026-07-10T23:42:27Z</updated>
    <author>
      <name>Christian Nwamba </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/developers-guide-state-management-effector"/>
    <content type="text"><![CDATA[<p>Learn to build a simple app that shows how Effector handles state, async operations and UI updates. The app will allow users add, update, delete and load todos from an API.</p><p>State management in React can get complicated quickly. Most libraries make you choose between simple and powerful. Simple tools break as your app grows or become difficult to manage. Powerful tools require you to write a lot of setup/config code before anything works. And when you need to handle async operations or derive state from multiple sources, you&rsquo;re writing custom logic from scratch all over again.</p><p><a target="_blank" href="https://effector.dev/">Effector</a> works differently. It is event-driven in the sense that you tell the app what happened (an event), the data updates in the store and the UI updates accordingly. Side effects are handled cleanly, and TypeScript works without extra setup. Instead of dispatching actions and writing reducers, you simply fire events that your stores react to.</p><h2 id="prerequisites">Prerequisites</h2><ul><li>Understanding of JavaScript/<a target="_blank" href="https://www.typescriptlang.org/">TypeScript</a></li><li>Basic familiarity with <a target="_blank" href="https://react.dev/">React</a></li></ul><h2 id="project-setup">Project Setup</h2><p>We&rsquo;re going to build a to-do app to see how Effector handles state, async operations and UI updates. The app will let users add, update, delete and load todos from an API. We&rsquo;ll use Vite to set up a React + TypeScript project.</p><p>Open your terminal and run the following command:</p><pre class=" language-shell"><code class="prism  language-shell">npm create vite@latest effector-todo -- --template react-ts 
</code></pre><p>Once that is done, run the following command to navigate into your project:</p><pre class=" language-shell"><code class="prism  language-shell">cd effector-todo
npm install
</code></pre><p>Run this command to install Effector dependencies:</p><pre class=" language-shell"><code class="prism  language-shell">npm install effector effector-react
</code></pre><p>Effector works with any framework, but we need <code>effector-react</code> to connect it to React. The core <code>effector</code> package handles state management, while <code>effector-react</code> provides hooks like <code>useUnit</code> to access state in components.</p><h2 id="what-is-effector">What Is Effector?</h2><p>Effector is built around events. All you need to do is describe what happened and the store updates, and the UI will follow. If we compare that to Redux, you need an action, a reducer and a type constant to update a single value in a component.</p><p><a target="_blank" href="https://zustand.docs.pmnd.rs/learn/getting-started/introduction">Zustand</a> made this simpler by letting us call functions directly on the store, which felt like a relief. But async operations are where things get complicated. Suppose we want to save a todo to a database before updating the screen. The fetch call, the loading flag and error handling will all end up in one place, making the function grow messy.</p><p>Effector handles async operations differently. We wrap them in an effect, and the loading, success and failure states are all tracked automatically. With this, there is no need for manual flag management.</p><p>Then we also have <a target="_blank" href="https://react.dev/learn/passing-data-deeply-with-context">React Context</a>. If you change anything in a provider, your entire component tree re-renders. Effector avoids this by only updating the specific components subscribed to the store that actually changed. TypeScript also works out of the box. If you define types once in the store, they are known everywhere in the codebase.</p><p>The powerful thing about Effector is that it isn&rsquo;t tied to React alone. It gives you the flexibility to work with <a target="_blank" href="https://vuejs.org/">Vue</a>, <a target="_blank" href="https://svelte.dev/">Svelte</a> or any other framework.</p><h3 id="the-3-building-blocks">The 3 Building Blocks</h3><p>As mentioned earlier, Effector is built around three primitives called units: stores, events and effects. Everything in your app is one of these three things.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/effector-building-blocks.png?sfvrsn=d749548a_2" title="Effector’s building blocks" alt="Effector’s building blocks" /></p><ul><li><strong>A store</strong> holds your data, and it is a reactive container. When it changes, every component subscribed to it updates automatically. More precisely, every part of your UI that depends on it updates automatically. You never have to tell React that something has changed or trigger a re-render. The store handles that.</li><li><strong>Events</strong> are signals. They represent things that happen in your app, such as a button being clicked, a form being submitted or a user typing something. An event doesn&rsquo;t contain logic itself, it just announces what happened and carries the relevant data (the payload). This separation is intentional. Because an event is just a signal, you can wire it to any store or effect without the UI caring. The React button just triggers the event, so it doesn&rsquo;t need to know what happens next. That&rsquo;s the store&rsquo;s job.</li><li><strong>Effects</strong> are where async operations live. Anytime your app needs to talk to the outside world (fetch data, write to an API or read from localStorage), that goes in an effect. The reason effects exist as a separate primitive is that async operations have a lifecycle. They start, they either succeed or fail, and the UI needs to reflect each of those states. In most libraries, you manage this yourself with <code>useState</code> hooks and <code>try/catch</code> blocks scattered across your component. Effector handles it automatically. Every effect gives you a <code>loading</code> state, a <code>success</code> state and an <code>error</code> state out of the box. All you need to do is connect them, and you&rsquo;re done.</li></ul><h2 id="building-the-todo-store">Building the Todo Store</h2><p>Create a src/store.ts file and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> createStore <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"effector"</span><span class="token punctuation">;</span>

<span class="token keyword">type</span> Todo <span class="token operator">=</span> <span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
  text<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
  done<span class="token punctuation">:</span> <span class="token keyword">boolean</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> $todos <span class="token operator">=</span> createStore<span class="token operator">&lt;</span>Todo<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In the code above, we have a <code>Todo</code> type for TypeScript, which is just the shape of one item in our todos array, a single todo. The <code>$</code> prefix is Effector&rsquo;s convention for signaling that this is a <code>store</code>, not a regular <code>variable</code>. Because we passed <code>Todo[]</code> as the type, everywhere we use <code>$todos</code>, TypeScript already knows exactly what&rsquo;s inside it. The code above is our entire data layer for todos.</p><h2 id="creating-the-events">Creating the Events</h2><p>A store on its own doesn&rsquo;t do much. We mentioned earlier that events are one of the three building blocks in Effector, and this is where we create them. Update your <code>src/store.ts</code> file with the following:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> createStore<span class="token punctuation">,</span> createEvent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"effector"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> addTodo <span class="token operator">=</span> createEvent<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> toggleTodo <span class="token operator">=</span> createEvent<span class="token operator">&lt;</span><span class="token keyword">number</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> deleteTodo <span class="token operator">=</span> createEvent<span class="token operator">&lt;</span><span class="token keyword">number</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Here we have three events that can happen in the app. <code>addTodo</code> carries a string, which is the text of the new todo. <code>toggleTodo</code> and <code>deleteTodo</code> carry a number which is the ID of the todo to act on.</p><p>One thing to notice here is that there&rsquo;s no logic. <code>addTodo</code> doesn&rsquo;t know how todos are stored or what happens when it fires. It&rsquo;s just a signal. This is what we described earlier when we said that the button that fires the event doesn&rsquo;t need to know what happens next.</p><h2 id="connecting-events-to-the-store">Connecting Events to the Store</h2><p>Right now, the store and the events exist independently, nothing connects them. That&rsquo;s what <code>.on()</code> does. Update your s<code>rc/store.ts</code> with the following:</p><pre class=" language-ts"><code class="prism  language-ts">$todos
<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>addTodo<span class="token punctuation">,</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> text<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span>
  <span class="token operator">...</span>state<span class="token punctuation">,</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> text<span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token keyword">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>toggleTodo<span class="token punctuation">,</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> id<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
  state<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
    todo<span class="token punctuation">.</span>id <span class="token operator">===</span> id<span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token operator">...</span>todo<span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token operator">!</span>todo<span class="token punctuation">.</span>done <span class="token punctuation">}</span> <span class="token punctuation">:</span> todo
  <span class="token punctuation">)</span>
<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>deleteTodo<span class="token punctuation">,</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> id<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
  state<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> todo<span class="token punctuation">.</span>id <span class="token operator">!==</span> id<span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Each <code>.on()</code> method takes two parameters: the event to listen for, and a function that describes how the state should change. The function receives the current state and the event payload, then returns a new state. It never mutates the previous state; instead, it always returns a new value.</p><p>In the code above, when <code>addTodo</code> fires, we spread the existing todos and add a new one. When <code>toggleTodo</code> fires, we find the todo with that ID and toggle its <code>done</code> value. When <code>deleteTodo</code> fires, we filter that todo out of the array.</p><p>That&rsquo;s the complete data layer for our todo app. There are no classes and no reducers. Just a store, three events and three <code>.on()</code> handlers describing exactly what changes when each event fires.</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">KendoReact vs. OSS: What You Can Actually Get for Free (and What You Can&rsquo;t)</h4></div><div class="col-8"><p class="u-fs16 u-mb0">If you&rsquo;ve reached the point where <a target="_blank" href="https://www.telerik.com/blogs/kendoreact-vs-oss-what-actually-get-free-what-you-cant">free UI libraries are starting to cause friction</a>, it may be time to consider whether they&rsquo;re still the right choice for your team&mdash;and your app.</p></div></div><hr class="u-mb3" /></aside><h2 id="connecting-to-react">Connecting to React</h2><p>Our store exists, the events are wired up, but our UI doesn&rsquo;t know any of that yet. This is where <code>effector-react</code> comes in. It gives you a single hook, <code>useUnit</code>, that connects your components to your stores.</p><h3 id="reading-state-with-useunit">Reading State with useUnit</h3><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> useUnit <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"effector-react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> $todos <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./store"</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> todos <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>$todos<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p><code>useUnit</code> subscribes the component to <code>$todos</code>. When the store changes, the component re-renders with the new value. If nothing changes, it doesn&rsquo;t re-render.</p><p>We don&rsquo;t have context providers wrapping our app here. Compare this to how you would do the same with Context:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token operator">&lt;</span>TodoContext<span class="token punctuation">.</span>Provider value<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> todos<span class="token punctuation">,</span> setTodos <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>App <span class="token operator">/</span><span class="token operator">&gt;</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>TodoContext<span class="token punctuation">.</span>Provider<span class="token operator">&gt;</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> todos <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useContext</span><span class="token punctuation">(</span>TodoContext<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Every time <code>setTodos</code> is called, every component inside that provider re-renders. As you can see, Effector gives us a much cleaner approach. With Effector, there&rsquo;s no provider. All we have to do is just import the store and call <code>useUnit</code>.</p><p>Create an <code>App.tsx</code> file in your <code>src</code> directory if you haven&rsquo;t already, and add the following to it:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useUnit <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"effector-react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> $todos<span class="token punctuation">,</span> addTodo<span class="token punctuation">,</span> toggleTodo<span class="token punctuation">,</span> deleteTodo <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./store"</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> todos <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>$todos<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>input<span class="token punctuation">,</span> setInput<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> <span class="token function-variable function">handleAdd</span> <span class="token operator">=</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">if</span> <span class="token punctuation">(</span>input<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 function">addTodo</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">setInput</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 keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>min-h-screen bg-gray-50 p-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>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>max-w-2xl mx-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>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-3xl font-bold text-gray-900 mb-8<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          Effector Todo
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white rounded-lg shadow p-6 mb-6<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex gap-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
              <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span>
              <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>input<span class="token punctuation">}</span></span>
              <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setInput</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
              <span class="token attr-name">onKeyPress</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> e<span class="token punctuation">.</span>key <span class="token operator">===</span> <span class="token string">"Enter"</span> <span class="token operator">&amp;&amp;</span> <span class="token function">handleAdd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span>
              <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Add a new todo...<span class="token punctuation">"</span></span>
              <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500<span class="token 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">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleAdd<span class="token punctuation">}</span></span>
              <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors<span class="token punctuation">"</span></span>
            <span class="token punctuation">&gt;</span></span>
              Add
            <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>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white rounded-lg shadow divide-y<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token punctuation">{</span>todos<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">0</span> <span class="token operator">?</span> <span class="token punctuation">(</span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>p-4 text-gray-500 text-center<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
              No todos yet<span class="token punctuation">.</span> Add one above<span class="token operator">!</span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
          <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>
            todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span></span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>p-4 flex items-center gap-3<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
                  <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>checkbox<span class="token punctuation">"</span></span>
                  <span class="token attr-name">checked</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>done<span class="token punctuation">}</span></span>
                  <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">toggleTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                  <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-5 h-5 text-blue-600 rounded<span class="token punctuation">"</span></span>
                <span class="token punctuation">/&gt;</span></span>
                <span class="token operator">&lt;</span>span className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token string">`flex-1 </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>todo<span class="token punctuation">.</span>done <span class="token operator">?</span> <span class="token string">"line-through text-gray-400"</span> <span class="token punctuation">:</span> <span class="token string">"text-gray-900"</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
                  <span class="token punctuation">{</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">}</span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
                  <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">deleteTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                  <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-3 py-1 text-sm text-red-600 hover:bg-red-50 rounded<span class="token punctuation">"</span></span>
                <span class="token punctuation">&gt;</span></span>
                  Delete
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
            <span class="token punctuation">)</span><span class="token punctuation">)</span>
          <span class="token punctuation">)</span><span class="token punctuation">}</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>`
</code></pre><p>In the code above, you&rsquo;ll notice we&rsquo;re not attaching any state logic in our <code>App</code> component, all thanks to Effector. It doesn&rsquo;t care how todos are stored, added or deleted. All it does is read <code>$todos</code> and trigger events when something happens.</p><p>The only place we&rsquo;re using <code>useState</code> is for the <code>input</code> field, which makes sense since that&rsquo;s just local UI state which doesn&rsquo;t need to live in the store.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/todo-app-using-effector-stores.gif?sfvrsn=3054f22d_2" title="Todo app using Effector stores" alt="Todo app using Effector stores" /></p><h3 id="derived-store-with-.map">Derived Store with .map()</h3><p>Our store works, and the UI is connected, but most apps aren&rsquo;t as straightforward as our todo app currently is. At some point, you might want to show only completed todos in one place, count remaining tasks somewhere else or filter by priority in another component. You can already see where this is heading.</p><p>What comes to mind first is filtering inside each component. That works until you need to change how something works and realize your logic is scattered across the app, where changing one thing breaks another.</p><p>Effector handles this with derived states. Instead of rewriting the same logic or recomputing values across components, you derive them once.</p><p>Let&rsquo;s update our <code>store.ts</code> file with these derived stores:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">const</span> $completedTodos <span class="token operator">=</span> $todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todos<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
  todos<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> todo<span class="token punctuation">.</span>done<span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> $activeTodos <span class="token operator">=</span> $todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todos<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
  todos<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token operator">!</span>todo<span class="token punctuation">.</span>done<span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> $remainingCount <span class="token operator">=</span> $todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>
  <span class="token punctuation">(</span>todos<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> todos<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token operator">!</span>todo<span class="token punctuation">.</span>done<span class="token punctuation">)</span><span class="token punctuation">.</span>length
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p><code>$todos.map()</code> is a method we call on a store. This might look familiar, but it&rsquo;s not the same as JavaScript&rsquo;s <code>array.map()</code>. When this one is called on a store, it returns a new store.</p><p>In Effector, when you call <code>.map()</code> on a store, it creates a new store that watches the original one. Whenever <code>$todos</code> updates, the derived store runs your transformation function and updates itself. This way, everything stays in sync automatically.</p><p>Effector also follows immutability. Nothing gets changed in place. Every time you derive something, you&rsquo;re creating a new value instead of modifying the existing one, and the transformation function handles that for you.</p><p>Let&rsquo;s see this in action by updating our <code>App.tsx</code> file to look like so:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token comment">//App.tsx</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useUnit <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"effector-react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  $activeTodos<span class="token punctuation">,</span>
  $completedTodos<span class="token punctuation">,</span>
  $remainingCount<span class="token punctuation">,</span>
  addTodo<span class="token punctuation">,</span>
  toggleTodo<span class="token punctuation">,</span>
  deleteTodo<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./store"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> activeTodos <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>$activeTodos<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> completedTodos <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>$completedTodos<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> remainingCount <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>$remainingCount<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>input<span class="token punctuation">,</span> setInput<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> <span class="token function-variable function">handleAdd</span> <span class="token operator">=</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">if</span> <span class="token punctuation">(</span>input<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 function">addTodo</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">setInput</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 keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>min-h-screen bg-gray-50 p-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>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>max-w-2xl mx-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>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex items-center justify-between mb-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>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-3xl font-bold text-gray-900<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Effector Todo<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>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-gray-500 text-sm<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token punctuation">{</span>remainingCount<span class="token punctuation">}</span> <span class="token punctuation">{</span>remainingCount <span class="token operator">===</span> <span class="token number">1</span> <span class="token operator">?</span> <span class="token string">"task"</span> <span class="token punctuation">:</span> <span class="token string">"tasks"</span><span class="token punctuation">}</span> remaining
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white rounded-lg shadow p-6 mb-6<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex gap-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
              <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span>
              <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>input<span class="token punctuation">}</span></span>
              <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setInput</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
              <span class="token attr-name">onKeyPress</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> e<span class="token punctuation">.</span>key <span class="token operator">===</span> <span class="token string">"Enter"</span> <span class="token operator">&amp;&amp;</span> <span class="token function">handleAdd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span>
              <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Add a new todo...<span class="token punctuation">"</span></span>
              <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500<span class="token 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">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleAdd<span class="token punctuation">}</span></span>
              <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors<span class="token punctuation">"</span></span>
            <span class="token punctuation">&gt;</span></span>
              Add
            <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>

        <span class="token punctuation">{</span>activeTodos<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white rounded-lg shadow divide-y mb-6<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token punctuation">{</span>activeTodos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span></span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>p-4 flex items-center gap-3<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
                  <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>checkbox<span class="token punctuation">"</span></span>
                  <span class="token attr-name">checked</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>done<span class="token punctuation">}</span></span>
                  <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">toggleTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                  <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-5 h-5 text-blue-600 rounded<span class="token punctuation">"</span></span>
                <span class="token punctuation">/&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex-1 text-gray-900<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
                  <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">deleteTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                  <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-3 py-1 text-sm text-red-600 hover:bg-red-50 rounded<span class="token punctuation">"</span></span>
                <span class="token punctuation">&gt;</span></span>
                  Delete
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
            <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token punctuation">)</span><span class="token punctuation">}</span>

        <span class="token punctuation">{</span>completedTodos<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm font-medium text-gray-500 mb-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
              Completed
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white rounded-lg shadow divide-y opacity-60<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
              <span class="token punctuation">{</span>completedTodos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span></span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>p-4 flex items-center gap-3<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
                    <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>checkbox<span class="token punctuation">"</span></span>
                    <span class="token attr-name">checked</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>done<span class="token punctuation">}</span></span>
                    <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">toggleTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                    <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-5 h-5 text-blue-600 rounded<span class="token punctuation">"</span></span>
                  <span class="token punctuation">/&gt;</span></span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex-1 line-through text-gray-400<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                    <span class="token punctuation">{</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">}</span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
                    <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">deleteTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                    <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-3 py-1 text-sm text-red-600 hover:bg-red-50 rounded<span class="token punctuation">"</span></span>
                  <span class="token punctuation">&gt;</span></span>
                    Delete
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
              <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token punctuation">)</span><span class="token punctuation">}</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>As seen above, the app component stays clean and just does what it is supposed to do.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/todo-app-with-derived-stores.gif?sfvrsn=f18cac48_2" title="A basic todo app with derived stores" alt="A basic todo app with derived stores" /></p><h2 id="async-operations-with-effects">Async Operations with Effects</h2><p>Every app eventually needs to talk to the outside world, and it may be through fetching data, saving something to a server or reading from storage. This is where most state management solutions make you manually create a loading flag, set it to true before the request, set it back to false when it finishes, handle the error case and clean up if the component unmounts. You end up writing the same boilerplate every time.</p><p>The good thing about Effector is that it has a dedicated concept for this called Effects.</p><h2 id="creating-an-effect">Creating an Effect</h2><p>Let&rsquo;s update our <code>store.ts</code> file by first adding a new import called <code>createEffect</code>. This handles fetching data and, more generally, any kind of side effect.</p><p>We&rsquo;ll also use a dummy API to fetch some todos and define the type of each todo we expect back.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> createStore<span class="token punctuation">,</span> createEvent<span class="token punctuation">,</span> createEffect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"effector"</span><span class="token punctuation">;</span>

<span class="token keyword">type</span> ApiTodo <span class="token operator">=</span> <span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
  todo<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
  completed<span class="token punctuation">:</span> <span class="token keyword">boolean</span><span class="token punctuation">;</span>
  userId<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> loadTodosFx <span class="token operator">=</span> <span class="token function">createEffect</span><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://dummyjson.com/todos?limit=5"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> data<span class="token punctuation">.</span>todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">:</span> ApiTodo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
    id<span class="token punctuation">:</span> todo<span class="token punctuation">.</span>id<span class="token punctuation">,</span>
    text<span class="token punctuation">:</span> todo<span class="token punctuation">.</span>todo<span class="token punctuation">,</span>
    done<span class="token punctuation">:</span> todo<span class="token punctuation">.</span>completed<span 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>In the code above, <code>createEffect</code> wraps an async function. The <code>Fx</code> suffix is an Effector convention in the sense that just as <code>$</code> signals a store, <code>Fx</code> signals an effect. Anyone reading the code immediately knows what they&rsquo;re dealing with.</p><p>The function inside is just a regular async function that fetches data, transforms it and returns it.</p><p>Effector offers three things out of the box:</p><ul><li><code>loadTodosFx.pending</code>: A store that is true while the effect is running and false when it finishes</li><li><code>loadTodosFx.doneData</code>: An event that fires with the return value when the effect succeeds</li><li><code>loadTodosFx.fail</code>: An event that fires with the error if something goes wrong</li></ul><p>We don&rsquo;t write any of this, and you&rsquo;ll see it in action when we connect the effects to the store.</p><h2 id="connecting-the-effect-to-the-store">Connecting the Effect to the Store</h2><p>We&rsquo;ll wire <code>doneData</code> to <code>$todos</code> the same way we wired events with <code>.on()</code>.</p><p>In your store.ts file, update the <code>$todos</code> connection to include the effect:</p><pre class=" language-ts"><code class="prism  language-ts">$todos
  <span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>addTodo<span class="token punctuation">,</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> text<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span>
    <span class="token operator">...</span>state<span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      text<span class="token punctuation">,</span>
      done<span class="token punctuation">:</span> <span class="token keyword">false</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>toggleTodo<span class="token punctuation">,</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> id<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
    state<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
      todo<span class="token punctuation">.</span>id <span class="token operator">===</span> id <span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token operator">...</span>todo<span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token operator">!</span>todo<span class="token punctuation">.</span>done <span class="token punctuation">}</span> <span class="token punctuation">:</span> todo<span 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">on</span><span class="token punctuation">(</span>deleteTodo<span class="token punctuation">,</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> id<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> state<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> todo<span class="token punctuation">.</span>id <span class="token operator">!==</span> id<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>loadTodosFx<span class="token punctuation">.</span>doneData<span class="token punctuation">,</span> <span class="token punctuation">(</span>_<span class="token punctuation">,</span> todos<span class="token punctuation">:</span> Todo<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> todos<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The only new thing in the code above is the last <code>.on()</code> call. Before now, the store was reacting to events we triggered manually. Now it&rsquo;s also reacting to the result of an async operation.</p><p>When <code>loadTodosFx.doneData</code> fires (which happens when the request succeeds), the store replaces the current todos with whatever came back from the API.</p><h2 id="using-the-fx-in-the-component">Using the Fx in the Component</h2><p>Now update your App.tsx to import <code>loadTodosFx</code> and read the loading state:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useUnit <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"effector-react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  $activeTodos<span class="token punctuation">,</span>
  $completedTodos<span class="token punctuation">,</span>
  $remainingCount<span class="token punctuation">,</span>
  addTodo<span class="token punctuation">,</span>
  toggleTodo<span class="token punctuation">,</span>
  deleteTodo<span class="token punctuation">,</span>
  loadTodosFx<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./store"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> activeTodos <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>$activeTodos<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> completedTodos <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>$completedTodos<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> remainingCount <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>$remainingCount<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> loadTodos <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>loadTodosFx<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> isLoading <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>loadTodosFx<span class="token punctuation">.</span>pending<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> <span class="token punctuation">[</span>input<span class="token punctuation">,</span> setInput<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> <span class="token function-variable function">handleAdd</span> <span class="token operator">=</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">if</span> <span class="token punctuation">(</span>input<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 function">addTodo</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">setInput</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 keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>min-h-screen bg-gray-50 p-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>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>max-w-2xl mx-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>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex items-center justify-between mb-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>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-3xl font-bold text-gray-900<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Effector Todo<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>

          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex items-center gap-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-teal-700 text-2xl font-extrabold<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
              <span class="token punctuation">{</span>remainingCount<span class="token punctuation">}</span> <span class="token punctuation">{</span>remainingCount <span class="token operator">===</span> <span class="token number">1</span> <span class="token operator">?</span> <span class="token string">"task"</span> <span class="token punctuation">:</span> <span class="token string">"tasks"</span><span class="token punctuation">}</span><span class="token punctuation">{</span><span class="token string">" "</span><span class="token punctuation">}</span>
              remaining
            <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>button</span>
              <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">loadTodos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span>
              <span class="token attr-name">disabled</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>isLoading<span class="token punctuation">}</span></span>
              <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 disabled:opacity-50<span class="token punctuation">"</span></span>
            <span class="token punctuation">&gt;</span></span>
              <span class="token punctuation">{</span>isLoading <span class="token operator">?</span> <span class="token string">"Loading..."</span> <span class="token punctuation">:</span> <span class="token string">"Fetch Todos"</span><span class="token punctuation">}</span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white rounded-lg shadow p-6 mb-6<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex gap-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
              <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span>
              <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>input<span class="token punctuation">}</span></span>
              <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setInput</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
              <span class="token attr-name">onKeyPress</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> e<span class="token punctuation">.</span>key <span class="token operator">===</span> <span class="token string">"Enter"</span> <span class="token operator">&amp;&amp;</span> <span class="token function">handleAdd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span>
              <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Add a new todo...<span class="token punctuation">"</span></span>
              <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500<span class="token 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">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleAdd<span class="token punctuation">}</span></span>
              <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors<span class="token punctuation">"</span></span>
            <span class="token punctuation">&gt;</span></span>
              Add
            <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>

        <span class="token punctuation">{</span>activeTodos<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white rounded-lg shadow divide-y mb-6<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token punctuation">{</span>activeTodos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span></span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>p-4 flex items-center gap-3<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
                  <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>checkbox<span class="token punctuation">"</span></span>
                  <span class="token attr-name">checked</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>done<span class="token punctuation">}</span></span>
                  <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">toggleTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                  <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-5 h-5 text-blue-600 rounded<span class="token punctuation">"</span></span>
                <span class="token punctuation">/&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex-1 text-gray-900<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
                  <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">deleteTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                  <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-3 py-1 text-sm text-red-600 hover:bg-red-50 rounded<span class="token punctuation">"</span></span>
                <span class="token punctuation">&gt;</span></span>
                  Delete
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
            <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token punctuation">)</span><span class="token punctuation">}</span>

        <span class="token punctuation">{</span>completedTodos<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm font-medium text-gray-500 mb-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
              Completed
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white rounded-lg shadow divide-y opacity-60<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
              <span class="token punctuation">{</span>completedTodos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span></span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>p-4 flex items-center gap-3<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
                    <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>checkbox<span class="token punctuation">"</span></span>
                    <span class="token attr-name">checked</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>done<span class="token punctuation">}</span></span>
                    <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">toggleTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                    <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-5 h-5 text-blue-600 rounded<span class="token punctuation">"</span></span>
                  <span class="token punctuation">/&gt;</span></span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex-1 line-through text-gray-400<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                    <span class="token punctuation">{</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">}</span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
                    <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">deleteTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                    <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-3 py-1 text-sm text-red-600 hover:bg-red-50 rounded<span class="token punctuation">"</span></span>
                  <span class="token punctuation">&gt;</span></span>
                    Delete
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
              <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token punctuation">)</span><span class="token punctuation">}</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Two things changed in this component. First, we imported <code>loadTodosFx</code>, which is now called when the &ldquo;Load Todos&rdquo; button is clicked. Second, <code>loadTodosFx.pending</code> is read with <code>useUnit</code>, which automatically gives us the loading state. The button disables itself while loading, the label switches and todos appear when the fetch is complete.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/fetching-todos-from-api.gif?sfvrsn=2f979803_2" title="Fetching todos from an API" alt="Fetching todos from an API" /></p><h2 id="connecting-units-with-sample">Connecting Units with Sample</h2><p>We have stores, events and effects, but sometimes you need them to talk to each other. When one thing happens, it triggers something else. That&rsquo;s what <code>sample</code> is for. The idea here is straightforward: when a clock fires, read from a source, optionally transform the data and send it to a target.</p><p>Before we look at the code, let&rsquo;s break down what each of those terms actually means:</p><ul><li><strong>clock</strong> &ndash; The trigger. This is what starts everything. It can be an event, an effect or even another store. When it fires, everything else follows.</li><li><strong>source</strong> &ndash; The data you want to read at that moment. Usually a store.</li><li><strong>fn</strong> &ndash; An optional function to transform the data before it goes anywhere. If you don&rsquo;t need to transform anything, you can skip it.</li><li><strong>target</strong> &ndash; Where the result goes. Can be a store, an event or an effect.</li></ul><p>Here is an example:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> sample <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"effector"</span><span class="token punctuation">;</span>

<span class="token function">sample</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  clock<span class="token punctuation">:</span> someEvent<span class="token punctuation">,</span>    <span class="token comment">// when this fires...</span>
  source<span class="token punctuation">:</span> $someStore<span class="token punctuation">,</span>  <span class="token comment">// grab the current value of this store...</span>
  fn<span class="token punctuation">:</span> <span class="token punctuation">(</span>sourceValue<span class="token punctuation">,</span> clockPayload<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token operator">...</span><span class="token punctuation">,</span> <span class="token comment">// optionally transform...</span>
  target<span class="token punctuation">:</span> anotherEvent <span class="token comment">// and send it here</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Now, let&rsquo;s go through a real example from our todo app. Right now, when you add a todo, the list updates locally. But in a real app, you&rsquo;d want to reload from the server after adding so everything is in sync. Without <code>sample</code>, you&rsquo;d handle that inside the component by calling <code>addTodo</code>, then manually calling <code>loadTodosFx</code> right after. That works, but now that logic is tied to one specific button in one specific component.</p><p>Add this to your store.ts file:</p><pre class=" language-ts"><code class="prism  language-ts">Import <span class="token punctuation">{</span>sample<span class="token punctuation">}</span> <span class="token keyword">from</span> &ldquo;effector&rdquo;<span class="token punctuation">;</span> 
<span class="token function">sample</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  clock<span class="token punctuation">:</span> addTodo<span class="token punctuation">,</span>
  target<span class="token punctuation">:</span> loadTodosFx<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Now, instead of completely replacing the todos when the request finishes, we&rsquo;ll merge the data from the API with what we already have locally.</p><p>In your <code>store.ts</code> file, update the last <code>.on()</code> call to look like this:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>loadTodosFx<span class="token punctuation">.</span>doneData<span class="token punctuation">,</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> apiTodos<span class="token punctuation">:</span> Todo<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> apiIds <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span>apiTodos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>t<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> t<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> localTodos <span class="token operator">=</span> state<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span>t<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token operator">!</span>apiIds<span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span>t<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token operator">...</span>apiTodos<span class="token punctuation">,</span> <span class="token operator">...</span>localTodos<span 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>Every time <code>addTodo</code> fires from anywhere in our app, from any component, <code>loadTodosFx</code> runs automatically. The component has no idea this is happening. It just calls <code>addTodo</code>, and Effector handles the rest.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/connecting-units-to-sample.gif?sfvrsn=73c69da4_2" title="Connecting Units to Sample" alt="Connecting Units to Sample" /></p><h2 id="conclusion">Conclusion</h2><p>Honestly, Effector isn&rsquo;t the right tool for every project. If you&rsquo;re building something small with just a few components and basic state, stick with <code>useState</code> and <code>useContext</code>. Save Effector for when your app genuinely starts getting messy.</p><p>It shines in specific scenarios like when you&rsquo;re dealing with async operations that need proper loading and error handling, when multiple unrelated components need to access the same state, when you&rsquo;re computing the same derived data all over the place, or when you catch yourself copy-pasting the same async logic everywhere.</p><p>We&rsquo;ve only scratched the surface here. Effector can do much more, but we&rsquo;ve covered the basics and core concepts, which are the foundation for everything else. If you want to go deeper, check out the <a target="_blank" href="https://effector.dev/en/introduction/get-started/">Effector documentation</a>.</p>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:0dac30b3-0498-4120-aa1e-c48cc3032b86</id>
    <title type="text">3 Tricks to Help You Stop Procrastinating</title>
    <summary type="text">You have a lot on your plate. But rather than get any of it done, you seek out distractions. If you find yourself procrastinating at work, this post has three tips to help you break this pattern.</summary>
    <published>2026-07-02T12:24:05Z</published>
    <updated>2026-07-10T23:42:27Z</updated>
    <author>
      <name>Suzanne Scacca </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/3-tricks-help-stop-procrastinating"/>
    <content type="text"><![CDATA[<p><span class="featured">You have a lot on your plate. But rather than get any of it done, you seek out distractions. If you find yourself procrastinating at work, this post has three tips to help you break this pattern.</span></p><p>Procrastination isn&rsquo;t usually an issue of laziness or a lack of time-management skills. If we&rsquo;re talking about chronic procrastination, psychologists suggest it&rsquo;s an issue having more to do with self-regulation. It goes like this:</p><ul><li>You have an important task to do, be it big or small.</li><li>You know that if you don&rsquo;t do the task or get it done on time, it&rsquo;s going to create a problem for you (and probably others as well).</li><li>Yet, you willingly delay the task, knowing full well the consequences.</li><li>The distractions you seek out feel good, but it&rsquo;s only temporary.</li></ul><p>In this post, we&rsquo;re going to look at some of the reasons why people procrastinate and various tips and tricks you can do to push past it.</p><h2 id="why-do-we-procrastinate">Why Do We Procrastinate?</h2><p><a target="_blank" href="https://www.psychologytoday.com/us/basics/procrastination">According to Psychology Today</a>:</p><blockquote><p>&ldquo;Everyone puts things off sometimes, but procrastinators chronically avoid difficult tasks and may deliberately look for distractions. Procrastination tends to reflect a person&rsquo;s struggles with self-control. For habitual procrastinators, who represent approximately 20 percent of the population, &lsquo;I don&rsquo;t feel like it&rsquo; comes to take precedence over their goals or responsibilities, setting them on a downward spiral of negative emotions that further deters future effort.&rdquo;</p></blockquote><p>But why exactly do procrastinators <em>not feel like it</em>? There are a number of reasons.</p><p>For some, it&rsquo;s the pressure to be perfect and the fear of failing to live up to that standard that keeps them from getting started.</p><p>For others, it&rsquo;s because they perceive the task as being unenjoyable. So, they seek out something that will bring them joy, even temporarily.</p><p>Here are some other reasons why people may procrastinate:</p><ul><li>The task seems too big to handle.</li><li>They see little or no reward in doing it.</li><li>They&rsquo;re confused about how to do the task.</li><li>They feel overstimulated.</li><li>They feel fatigued.</li></ul><p>There are some mental health practitioners who suggest that there&rsquo;s sometimes something else at play.</p><p><a target="_blank" href="https://www.psychologytoday.com/us/blog/in-practice/202512/youre-not-a-procrastinator-youre-a-batcher">Dr. Alice Boyes</a>, for instance, says that &ldquo;batchers&rdquo; are often confused for procrastinators. Batchers are people who prefer to complete a set of tasks in a way that maximizes their productivity.</p><p>There are seven types. These are the ones most relevant to designers and developers:</p><ol><li>The time-based batcher waits to do certain tasks at specific times of the day instead of the second they hit their plate.</li><li>The volume-based batcher waits until they&rsquo;ve accumulated enough tasks and then cranks them out all at once.</li><li>The pressure-based batcher waits until they&rsquo;re closer to the delivery date (just not too close to miss it).</li><li>The context-based batcher waits until their physical environment is ideal (like the kids going to bed at night).</li><li>The identity-based batcher waits until a pre-determined time when they work in that capacity (like doing onboarding only on Mondays, wireframes on Tuesday, etc.)</li></ol><p>For some procrastinators, it&rsquo;s not about being irresponsible and delaying a task that needs to get done. It&rsquo;s that they have a preferred work method that only resembles procrastination.</p><h2 id="tricks-to-help-prevent-procrastination">3 Tricks to Help Prevent Procrastination</h2><p>Procrastination can feel good in the moment, though many people realize deep down inside the consequences won&rsquo;t feel very good. Here are some of the consequences that can result from procrastination:</p><ul><li>You wait until the last minute, forcing other critical tasks to go on the backburner.</li><li>You rush through the task, delivering it with errors, bugs, inconsistencies or other quality issues.</li><li>You feel stressed and overwhelmed, which leaves you in a heightened state of aggravation the rest of the day.</li><li>You miss your deadline. Your boss or client is displeased with you, which may keep you from better opportunities or advancements down the road.</li><li>You regularly procrastinate, which inevitably leads to sleepless nights, health issues and burnout.</li></ul><p>If you&rsquo;re worried you&rsquo;re headed down this path, here are some tricks you can use to stop procrastinating:</p><h2 id="use-a-task-management-tool">1. Use a Task Management Tool</h2><p>There are a couple of issues that can be resolved by <a target="_blank" href="https://www.telerik.com/blogs/4-project-management-strategies-help-build-professional-credibility">using a project-management tool</a> to schedule your tasks.</p><p>Let&rsquo;s say your boss calls you up and tells you they need a landing page built by Friday for a new Facebook ad campaign. You&rsquo;ve got it on your mind all week, but you keep dragging your feet. You hate building landing pages and would rather focus on maintaining and updating their website.</p><p>There&rsquo;s a big difference between knowing you have a task to do versus seeing it on a timeline or task list in front of you. That said, you might still feel a sense of pressure whenever you see this looming task.</p><p>What may help is having a tool that allows you to create an actionable and fully editable plan for the day, week and month ahead.</p><p>My suggestion is to find a scheduler that:</p><h3 id="allows-you-to-plan-your-days-down-to-the-hour">Allows You to Plan Your Days Down to the Hour</h3><p>Instead of just adding a three-hour task to build the landing page, you can set aside specific hours when you know you will be ready and able to get it done.</p><p><a target="_blank" href="https://www.atlassian.com/blog/productivity/find-productive-hours">Everyone&rsquo;s most productive hours</a> are different. If you haven&rsquo;t found yours yet, spend some time looking into it so you can schedule different kinds of tasks when you&rsquo;re mentally and energetically up to the challenge.</p><h3 id="comes-with-drag-and-drop-capabilities">Comes with Drag-and-Drop Capabilities</h3><p>If you&rsquo;re not feeling up to a certain task but it&rsquo;s up next on your schedule, simply drag it to a new time slot where you can reasonably tackle it.</p><p>This is why I love calendar-based time management tools. When you can see the whole week or even month ahead, <em>and</em> your deadlines are clearly marked, you can shift things around to suit how you&rsquo;re feeling in that moment.</p><h3 id="enables-you-to-build-in-free-time-or-buffers">Enables You to Build in Free Time or Buffers</h3><p>If you&rsquo;re filling your schedule to the brim every day with no wiggle room, it&rsquo;s going to make any level of procrastination worse. So, give yourself some breathing room.</p><p>For instance, I give myself a two-hour break in the middle of every work day. I don&rsquo;t have to use it all. But just having it on the calendar gives me the grace to work when I&rsquo;m up to the task instead of wasting my time on social media, Reddit, etc.</p><h3 id="allows-you-to-check-off-tasks-as-you-finish-them">Allows You to Check Off Tasks as You Finish Them</h3><p>The physical (or digital) act of <a target="_blank" href="https://www.atlassian.com/blog/productivity/the-psychology-of-checklists-why-setting-small-goals-motivates-us-to-accomplish-bigger-things">checking an item off a task list releases a hit of dopamine</a>.</p><p>One of the reasons why procrastinators seek out distractions is to activate their pleasure center. By setting up your task manager to create a similar sensation (and one that comes with rewards in the end instead of consequences), it may become addictive in a positive way.</p><h2 id="make-the-task-smaller">2. Make the Task Smaller</h2><p>A lot of times, it&rsquo;s the size of the task that intimidates people and leads them to procrastinate. For example, let&rsquo;s say you&rsquo;re <a target="_blank" href="https://www.telerik.com/blogs/design-systems-developers">building a design system</a> for a new app you&rsquo;re working on. You&rsquo;re dreading the task because of how long or complex it&rsquo;s been in the past. You have a six-hour block on your calendar to get it done and you keep pushing it back.</p><blockquote><p><strong>10:00 a.m. - 4:00 p.m.: CREATE DESIGN SYSTEM FOR CLIENT A</strong></p></blockquote><p>So, how about this?</p><p>Look at your deadline. Do you have some time before it needs to be done? Great. Then rather than set aside six hours (or however long you think it&rsquo;ll take), create a 15-minute task for your next free moment:</p><blockquote><p><strong>10:00 a.m. - 10:15 a.m.: Duplicate design system for Client X and save to Client A folder</strong></p></blockquote><p>Create a copy of the design system from the previous job, and save it in the project folder you&rsquo;re currently working on. While you&rsquo;re in there, update the basic client details so you don&rsquo;t have to worry about it later.</p><p>Not ready to do more right now? That&rsquo;s fine. Add a new 30-minute task to your schedule when you have the time, energy or focus:</p><blockquote><p><strong>3:30 p.m. - 4:00 p.m.: Swap out colors in design system for Client A&rsquo;s</strong></p></blockquote><p>You can do this with the remainder of the steps required to finish the overarching task.</p><p>For a lot of procrastinators, this approach can make difficult or time-consuming tasks feel more manageable. So long as you keep an eye on that deadline, you can make these small, incremental steps toward completing the whole task over time instead of all at once.</p><h2 id="cut-down-on-your-decision-making">3. Cut Down on Your Decision-making</h2><p>There&rsquo;s a <a target="_blank" href="https://lawsofux.com/choice-overload/">UX Law called Choice Overload</a>. It states that:</p><blockquote><p>&ldquo;Overchoice or choice overload is the paradoxical phenomenon that choosing between a large variety of options can be detrimental to decision making processes.&rdquo;</p></blockquote><p>We see this in UX design all the time. When you give users far too many choices to make or too many options to choose from, some of them just decide it&rsquo;s best to make no choice at all.</p><p>How does this play into procrastination?</p><p>Let&rsquo;s say you have four web development projects you&rsquo;re working on this month. They&rsquo;re all at varying stages. You look at the calendar for today and see the following tasks:</p><ul><li>1-hour kickoff call with Client B</li><li>30-minute weekly check-in with team</li><li>3 separate 30-minute user testing sessions to moderate for Client A</li><li>2 hours of market research for Client C</li><li>3 hours of user persona development for Client D</li><li>32 unread emails</li><li>11 unread Slack messages</li></ul><p>The first three you <em>have</em> to do. The problem is, they&rsquo;re scattered haphazardly throughout the day. So, trying to get the market research and user persona work done in one single stretch is going to be hard. You tell yourself you&rsquo;d much rather do that work than check your messages, but you just can&rsquo;t get started.</p><p>Those unread messages are weighing on you. You know that checking them would be the quickest thing to do and it wouldn&rsquo;t be a big deal if they get disrupted by the calls or user testing sessions. However, you know they might add more work (and possibly stress) to your plate.</p><p>So, what do you do?</p><p>The more brainpower you expend on &ldquo;What should I do next?&rdquo; or &ldquo;How do I avoid this task I&rsquo;m dreading,&rdquo; the more energy you&rsquo;re sapping away from work you need to do. The best thing is to reduce the number of decisions you have to make.</p><p>When it comes to managing tasks, you can do this by having dedicated hours for when you do certain things, like the time-based batcher method mentioned above.</p><p>For example, you might hold space on your calendar every day from 8:00 to 8:30 a.m. and again from 4:30 to 5:00 p.m. to check messages. By doing this, the 32 emails and 11 Slack messages no longer become something you have to contend with when figuring out what to do next.</p><p>Another thing you could do is set rules for when you can be scheduled and for what kinds of tasks. For instance, you could have dedicated days for meetings and calls. What&rsquo;s more, you could restrict those calls to a set timeframe, like between 9:00 a.m. and 12:00 p.m. This way, your calls wouldn&rsquo;t be spread out all over the place, making it challenging to get larger tasks done.</p><h2 id="wrapping-up">Wrapping Up</h2><p>We procrastinate because we anticipate some sort of discomfort or displeasure at performing a task. It could be that we believe the task will be too hard, that we won&rsquo;t be able to do a good job or that it&rsquo;ll bore our brains out.</p><p>Some people turn toward distractions that temporarily pause those feelings that have arisen. The only problem is that the joy and relief that come from those distractions are not long-lasting. What&rsquo;s more, procrastination can exacerbate the consequences of not doing the task when you had initially planned to.</p><p>Rather than get stuck with this kind of habit whenever you feel the urge to not do something, train yourself to develop new habits. Schedule all your tasks, but allow yourself the flexibility to move things around as needed. Break up bigger tasks into smaller steps to reduce overwhelm. And come up with rules so you&rsquo;re not having to expend so much mental energy on what to work on and when.</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">Navigating Turmoil and Chaos at Work Like a Pro</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Struggling to quiet the chaos around you? These four strategies might <a target="_blank" href="https://www.telerik.com/blogs/navigating-turmoil-chaos-work-like-pro">help you navigate the turmoil</a> arising inside and outside of your workspace.</p></div></div></aside>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:679fe682-4514-4e7a-94ff-ef3f94efed17</id>
    <title type="text">Replicating a Travel App in .NET MAUI</title>
    <summary type="text">Practice thoughtful planning before you begin coding with this .NET MAUI travel app. We’ll divide the design into blocks and code each one.</summary>
    <published>2026-07-01T16:48:23Z</published>
    <updated>2026-07-10T23:42:27Z</updated>
    <author>
      <name>Leomaris Reyes </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/replicating-travel-app-net-maui"/>
    <content type="text"><![CDATA[<p><span class="featured">Practice thoughtful planning before you begin coding with this .NET MAUI travel app. We&rsquo;ll divide the design into blocks and code each one.</span></p><p>Take note of this: always&mdash;always&mdash;absolutely always&mdash;when you start developing an app, take a moment to step back and analyze what you truly need. That way, you avoid writing the same code two, three or even N times.</p><p>Once you begin, aim to keep your code as clean and optimized as possible. Remember that every component you choose is a decision that shapes the quality of your app from the layout you select (where everything begins) to the components you use and the reasoning behind them. And of course, becoming more comfortable with XAML every day is key. With creativity and a willingness to think outside the box, anything can be achieved in a UI.</p><p>With practice, this process becomes easier, as experience gives you the insight needed to make faster and more confident decisions. That&rsquo;s why in this article we will replicate a travel UI from scratch, inspired by a design obtained from <a target="_blank" href="https://dribbble.com/shots/26145161-Travel-app-design">Dribbble</a>.</p><p><strong>How will the explanation work?</strong></p><p>So you can understand everything 100%, I&rsquo;ll explain how the process will work:</p><p>➖<strong>Visual diagram:</strong> Before we start, you&rsquo;ll see a diagram with a screenshot of the design we want to achieve. This design will be divided into blocks, each identified with a name and a color. Each block will be explained individually.</p><p>➖<strong>Code explanation per block:</strong> In addition to the text explanation, each block will include the exact code snippet you need to write to achieve the result.</p><p>➖<strong>Step-by-step visual progress:</strong> Each explanation will have its corresponding screenshot, so you can see the progress as we build the UI.</p><p>⚠️ For the purposes of these articles, there will be some changes to the original user interface.</p><h2 id="-environment-setup"> Environment Setup</h2><p>You&rsquo;ll learn how to take advantage of some of the powerful components provided in the Progress Telerik UI for <a target="_blank" href="https://www.telerik.com/maui-ui">.NET MAUI component library</a>. Before we dive in, let&rsquo;s get your environment ready, just keep these two key points in mind:</p><ol><li><p><strong>If you don&rsquo;t have a <a target="_blank" href="https://www.telerik.com/account/">Telerik account</a> yet, you can create one for free.</strong> You&rsquo;ll get access to a trial license so you can explore not only RadBorder and RadButton, but all the Telerik controls for .NET MAUI.</p></li><li><p><strong>You need to install Telerik UI for .NET MAUI.</strong> This is a one-time setup, meaning you don&rsquo;t need to do it for every component you use. (If you don&rsquo;t have it installed yet, I&rsquo;ve included an article where it is explained step by step how to set it up in both <a target="_blank" href="https://www.telerik.com/maui-ui/documentation/get-started/first-steps-vs">Visual Studio</a> and <a target="_blank" href="https://www.telerik.com/maui-ui/documentation/get-started/first-steps-vs-code">Visual Studio Code</a>.)</p></li></ol><h2 id="breaking-down-the-design-into-blocks">Breaking Down the Design into Blocks</h2><p>To make this easier to follow, I&rsquo;ve divided the design into clear blocks. We&rsquo;ll build each part one at a time, in the order you see below.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/01_visual_structure.png?sfvrsn=6c886051_2" title="Visual structure" alt=".NET MAUI travel app structure" /></p><p>Alright, we&rsquo;ve now divided our UI into blocks. Grab a cup of coffee (or hot chocolate), and let&rsquo;s start writing some code! </p><h2 id="main-image">1. Main Image</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/02_main_image_block.png?sfvrsn=308faa3_2" title="Main imagen block" alt=".NET MAUI travel app main image" /></p><p>When starting to build a UI, the first thing you should evaluate is which layout best fits your needs. In this case, we need a flexible layout that allows us to create overlapping effects both for positioning text on top of the image and for building the overlapping effect in the second block.</p><p>For this, we&rsquo;ll use a Grid, structured as follows:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Grid RowDefinitions="auto,*"&gt;  
    &lt;!-- Place here the remaining elements that belong to the first block--&gt; 
    &lt;!-- Insert here the code for the next block --&gt;     
&lt;/Grid&gt;
</code></pre><p>Now, let&rsquo;s add the main image along with the two text elements displayed on top of it. Place this code in the section indicated by the comment: <code>&lt;!-- Place here the remaining elements that belong to the first block --&gt;</code>.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Image Grid.Row="0" Source="homebg" Aspect="Fill" HeightRequest="500"/&gt; 

&lt;Label Grid.Row="0" Text="Wanna Go List" TextColor="White" FontSize="24" FontAttributes="Bold" 
    TranslationY="-40" 
    HorizontalTextAlignment="Center" 
    VerticalTextAlignment="Center"/&gt; 

&lt;Label Grid.Row="0" Text="Save only your favorite hotels.&amp;#10;Search only your favorite hotels." 
    TextColor="White" FontSize="17" TranslationY="-65" 
    HorizontalTextAlignment="Center" 
    VerticalTextAlignment="End"/&gt;
</code></pre><p>✍️ To help create the overlapping effect across the Grid areas, I used the <code>TranslationY</code> property to position the element exactly where needed.</p><h2 id="sign-in-details">2. Sign-in Details</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/03_sign_in_details_block.png?sfvrsn=d4b404c0_2" title="Sign In details block" alt=".NET MAUI travel app sign in" /></p><p>For this second block, we&rsquo;ll work with several elements, all contained within a white background with rounded top corners. This is where Telerik RadBorder plays a key role.</p><p>Inside this container, we&rsquo;ll include:</p><ul><li>Rounded and rectangular buttons (using Telerik RadButton)</li><li>Simple labels and styled text (using FormattedText)</li></ul><h3 id="white-background-with-rounded-corners">White Background with Rounded Corners</h3><p>To get started with RadBorder, add the corresponding namespace:</p><pre class=" language-xml"><code class="prism  language-xml">xmlns:telerik="clr-namespace:Telerik.Maui.Controls;assembly=Telerik.Maui.Controls"
</code></pre><p>Once that&rsquo;s set up, add the component as shown below.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;telerik:RadBorder Grid.Row="1" 
    BackgroundColor="White" 
    VerticalOptions="Fill" 
    Margin="0,-40,0,0" 
    CornerRadius="30" 
    Padding="30"&gt; 
    &lt;!-- Add the Grid here-- &gt; 
&lt;/telerik:RadBorder&gt;
</code></pre><p>Inside the RadBorder, we&rsquo;ll use a Grid to structure the content. This Grid will consist of four rows and three columns, with a spacing of 20 between elements to maintain a clean and well-organized layout.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Grid RowDefinitions="auto,auto,auto,auto" ColumnDefinitions="*,*,*" RowSpacing="20"&gt; 
    &lt;!-- Add all remaining elements for the second block here --&gt; 
&lt;/Grid&gt;
</code></pre><p>Finally, let&rsquo;s add all the remaining elements inside the Grid. Here are a few key points to keep in mind:</p><p>➖ For the buttons, we&rsquo;ll use Telerik RadButton. Since you already added the namespace earlier, there&rsquo;s no need to include it again.</p><p>➖ To achieve a rounded button, simply set the <code>WidthRequest</code> and <code>HeightRequest</code> to the same value, and define the <code>CornerRadius</code> as half of that value.</p><p>➖ For the label with multiple colors, instead of using several separate labels, we&rsquo;ll use <code>FormattedText</code>. This helps keep the code cleaner and more efficient.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;telerik:RadButton Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Text="Sign In Via Email" TextColor="White" BackgroundColor="#0c538f" CornerRadius="8"/&gt;

&lt;Label Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Text="or sign in with" FontSize="13" HorizontalTextAlignment="Center" TextColor="Grey"/&gt;

&lt;telerik:RadButton Grid.Row="2" Grid.Column="0" ImageSource="google" BackgroundColor="#def0f5" HeightRequest="60" WidthRequest="60" CornerRadius="30" HorizontalOptions="End"/&gt;
 
&lt;telerik:RadButton Grid.Row="2" Grid.Column="1" ImageSource="apple" BackgroundColor="#def0f5" HeightRequest="60" WidthRequest="60" CornerRadius="30"/&gt;
 
&lt;telerik:RadButton Grid.Row="2" Grid.Column="2" ImageSource="facebook" BackgroundColor="#def0f5" HeightRequest="60" WidthRequest="60" CornerRadius="30" HorizontalOptions="Start"/&gt;
 
&lt;Label Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3" HorizontalTextAlignment="Center"&gt;

&lt;Label.FormattedText&gt; 
    &lt;FormattedString&gt; 
    &lt;Span Text="Don't have an account? " TextColor="Grey"/&gt; 
    &lt;Span Text="Sign Up" FontAttributes="Bold" TextColor="#0c538f"/&gt; 
    &lt;/FormattedString&gt; 
    &lt;/Label.FormattedText&gt; 
&lt;/Label&gt;
</code></pre><h2 id="header">3. Header</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/04_header_block.png?sfvrsn=77918cc2_2" title="Header block" alt=".NET MAUI travel app header" /></p><p>Woohoo!!!  Our first screen is ready.  Now, in this third block, we&rsquo;ll start building the second screen packed with some really interesting elements!</p><p>Let&rsquo;s begin with the main layout. We&rsquo;ll create a three row Grid where we&rsquo;ll position the header image, a VerticalStackLayout to hold the plans and benefits and the footer.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Grid RowDefinitions="auto,*,auto,auto" RowSpacing="20" Padding="20,0"&gt; 
    &lt;!-- Add the header image code here --&gt; 
    &lt;!-- Add the VerticalStackLayout here &rarr; 
    &lt;!-- Add the footer code here --&gt; 
&lt;/Grid&gt;
</code></pre><p>To get started, we&rsquo;ll focus on placing the header image and the primary label.</p><h3 id="header-image">Header Image</h3><p>You can either use an image that already has a diagonal effect or take a regular image and create that effect through code. For this demo, I used a regular image and rotated it to show you how it works. This effect comes from combining <code>Rotation</code>, <code>TranslationY</code>, and <code>TranslationX</code> properties, along with adjusting the width and height.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Image Grid.Row="0" Source="header" HeightRequest="370" WidthRequest="500" Aspect="AspectFit" 
    Rotation="-15" 
    TranslationX="-20" 
    TranslationY="-300"/&gt;
</code></pre><h3 id="main-label">Main Label</h3><p>Before adding the label itself, we&rsquo;ll set up the layout that will contain it. Add a VerticalStackLayout, and inside it place a Label with FormattedText. This allows you to apply different colors, sizes and styles within a single label, keeping your UI clean and flexible.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;VerticalStackLayout Grid.Row="0" Margin="0,140,0,0"&gt; 
&lt;Label HorizontalTextAlignment="Center" FontSize="28" CharacterSpacing="18"&gt; 
&lt;Label.FormattedText&gt; 
    &lt;FormattedString&gt; 
    &lt;Span Text="Unlock " FontAttributes="Bold"/&gt; 
    &lt;Span Text="Pro&amp;#10;" FontAttributes="Bold" TextColor="#4b9db4"/&gt; 
    &lt;Span Text="Features! " FontAttributes="Bold"/&gt; 
    &lt;/FormattedString&gt; 
&lt;/Label.FormattedText&gt; 
&lt;/Label&gt;
 
&lt;!-- Add the Benefits code block here --&gt; 
&lt;!-- Add the Plans code block here --&gt;
 
&lt;/VerticalStackLayout&gt;
</code></pre><h2 id="benefits--plans">4. Benefits &amp; Plans</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/05_benefits_and_plans.png?sfvrsn=897d8827_2" title="Benefits and plans block" alt=".NET MAUI travel app benefits and plans" /></p><p>For this block, we&rsquo;ll also use Telerik RadBorder, so make sure to include the same namespace used on the previous page here as well. This section is composed of the following elements:</p><p>➖ <strong>Benefits:</strong> We&rsquo;ll use a CollectionView so the information can be loaded from a flexible list, instead of adding each item manually in XAML. Each item will include a checkmark image and a label with the benefit name.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;CollectionView.ItemTemplate&gt; 
&lt;DataTemplate&gt; 
    &lt;HorizontalStackLayout Spacing="10" Padding="0,8"&gt; 
    &lt;Image Source="check" HeightRequest="20" WidthRequest="20"/&gt; 
    &lt;Label Text="{Binding Description}" FontSize="12"/&gt; 
    &lt;/HorizontalStackLayout&gt; 
    &lt;/DataTemplate&gt; 
&lt;/CollectionView.ItemTemplate&gt; 
&lt;/CollectionView
</code></pre><p>➖<strong>Plans:</strong> We&rsquo;ll also use a CollectionView for the plan selector. Each item will be displayed inside a box with rounded blue borders and will contain the plan name, the discount, the current price and the previous price.</p><pre class=" language-xml"><code class="prism  language-xml">&lt;CollectionView VerticalScrollBarVisibility="Never" 
ItemsSource="{Binding plans}"&gt; 
    &lt;CollectionView.ItemTemplate&gt; 
    &lt;DataTemplate&gt; 
    &lt;telerik:RadBorder Grid.Row="1" 
    BorderColor="#b9d7e1" 
    BorderThickness="2" 
    CornerRadius="20" 
    Margin="0,10,0,0" 
    Padding="10,15"&gt; 
    &lt;Grid ColumnDefinitions="auto,auto,*,auto" VerticalOptions="Center"&gt; 
    &lt;Label Grid.Column="0" Text="{Binding Name}" FontSize="14" FontAttributes="Bold" VerticalTextAlignment="Center" /&gt;
     
    &lt;telerik:RadBorder Grid.Column="1" 
    BackgroundColor="#F2555A" 
    BorderThickness="2" 
    CornerRadius="50" 
    Padding="10,6"&gt;
    
    &lt;Label 
    Text="{Binding Discount}" 
    TextColor="White" 
    FontAttributes="Bold" 
    FontSize="12" 
    HorizontalTextAlignment="Center" 
    VerticalTextAlignment="Center" /&gt; 
    &lt;/telerik:RadBorder&gt;
     
    &lt;Label Grid.Column="2" Text="{Binding Price} " FontSize="14" VerticalTextAlignment="Center" HorizontalTextAlignment="End" FontAttributes="Bold"/&gt;
    
    &lt;Label Grid.Column="3" Text="{Binding OldPrice}" VerticalTextAlignment="Center" TextDecorations="Strikethrough" FontSize="14" TextColor="Gray"/&gt; 
    &lt;/Grid&gt; 
    &lt;/telerik:RadBorder&gt; 
    &lt;/DataTemplate&gt; 
    &lt;/CollectionView.ItemTemplate&gt; 
&lt;/CollectionView&gt;
</code></pre><h2 id="footer">5. Footer</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/06_footer.png?sfvrsn=c66819db_2" title="Footer block" alt=".NET MAUI travel app footer" /></p><p>Oh yeah! We&rsquo;ve reached the final block, the footer. This section includes a centered label and a button (using Telerik RadButton). To add it, go to the main Grid of this screen and locate the comment <code>&lt;!-- Add the footer code here --&gt;</code>.</p><p>Then, place the following code in that section:</p><pre class=" language-xml"><code class="prism  language-xml">&lt;Label Grid.Row="1" Text="Can be cancelled at any time" FontSize="13" TextColor="Grey" VerticalOptions="End" HorizontalTextAlignment="Center"/&gt;

&lt;telerik:RadButton Grid.Row="2" Text="Become Member" BackgroundColor="#0c538f" CornerRadius="10" VerticalOptions="End"/&gt;
</code></pre><p>And that&rsquo;s it&mdash;we&rsquo;re all done!  Below, you can see the final result of both screens.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/07_final_results.png?sfvrsn=ed18f275_2" title="Final results" alt=".NET MAUI travel app final result" /></p><h2 id="conclusion">Conclusion</h2><p>And that&rsquo;s it!  In this article, we explored how to build a travel UI using .NET MAUI with XAML, inspired by a modern design.</p><p>I hope this guide helps you take these ideas and practices and apply them to your own UI implementations, especially when working with layouts, overlapping elements, and Telerik components.</p><p>If you have any questions or would like me to dive deeper into a specific part, feel free to leave a comment, I&rsquo;ll be happy to help! </p><p>See you in the next article! &zwj;♀️</p><p>Remember, Telerik UI for .NET MAUI comes with a free 30-day trial. See what you can create:</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:2ec1f7bc-a277-4bcc-b3d7-ce4efd679c12</id>
    <title type="text">How Depending Leads to Independence</title>
    <summary type="text">True independence isn’t the absence of dependencies. It’s an intentional integration. An assembly that’s clear, chosen and changeable.</summary>
    <published>2026-07-01T13:19:44Z</published>
    <updated>2026-07-10T23:42:27Z</updated>
    <author>
      <name>Teon Beijl </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/how-depending-leads-independence"/>
    <content type="text"><![CDATA[<p><span class="featured">True independence isn&rsquo;t the absence of dependencies. It&rsquo;s an intentional integration. An assembly that&rsquo;s clear, chosen and changeable.</span></p><p><strong>It depends.</strong></p><p>If you ever ask a design question, most likely this is the answer. <em>It depends.</em></p><p>It&rsquo;s true. Everything depends on something else. There&rsquo;s no black or white, right or wrong answer, because it always depends. This is the context you&rsquo;d need to understand. How it&rsquo;s related.</p><p>This applies to your <a href="https://www.telerik.com/blogs/stop-running-your-backlog-like-emergency-room" target="_blank">backlog</a> as well. In previous articles, we covered priority and timing. When does something deserve attention, and in what order do you pick up work. And even when you know what to pick up, when matters.</p><p>So let&rsquo;s say you know what work to pick up and when to pick it up, the question still worth asking is: what does it depend on, and is anything else depending on it?</p><p>We call this &ldquo;dependency management.&rdquo; I think that means more than a dependency graph. It&rsquo;s about relationships and context.</p><h2 id="the-regulatory-reflex">The Regulatory Reflex</h2><p>We often manage dependencies well as part of backlog management to mitigate or address risk. And there&rsquo;s a reflex, a regulatory reflex, that makes us lean toward risk avoidance.</p><p>A dependency gets seen or projected as a negative thing. That risk, the thinking goes, can then be mitigated by reducing dependencies.</p><p>I&rsquo;ve seen this a lot in product development. &ldquo;Dependency management&rdquo; became a synonym for <em>reducing</em> dependencies.&nbsp;Avoid the vendor. Build it yourself. Own the code, own the outcome. Right?</p><p>It sounds strategic. But it rests on the wrong definition of independence.</p><h2 id="does-true-independence-actually-exist">Does True Independence Actually Exist?</h2><p>Here&rsquo;s the question to ask yourself:&nbsp;<strong>Does true independence actually exist?</strong></p><p>The word <em>independence</em> literally means &ldquo;not to hang from.&rdquo;</p><blockquote><p><em>In</em> (not) + <em>pendere</em> (to hang).</p></blockquote><p>The whole concept is built on negation.</p><p>But you always depend on something. A framework, team, budget or a market. Even the time you have in a day.</p><p>The question isn&rsquo;t <em>whether</em> you depend. It&rsquo;s what you depend on and whether that dependency works.</p><p>Fortunately, there&rsquo;s another way to read that same prefix.</p><p>The <em>in-</em> in independence has another root. The one in <em>include</em>, <em>inject</em>, <em>integrate</em>, <em>insight</em>. <em>In</em> as <em>into</em>, <em>within</em>, <em>part of</em>. Not negation. <strong>Integration.</strong></p><p>Read that way, independence doesn&rsquo;t mean &ldquo;not hanging from.&rdquo; It means &ldquo;hanging in.&rdquo; Being part of something. Integrated into a larger system. Intentional.</p><p>That&rsquo;s a very different idea than avoidance.</p><p>You&rsquo;re not running from dependencies. You&rsquo;re choosing which ones to integrate into. Seeing them clearly. Selecting them deliberately. Keeping the freedom to shift them when the system needs to evolve.</p><p>Not the absence of dependencies. The presence of deliberate ones.</p><p>A purposeful assembly of parts. That&rsquo;s what we should mean when we say &ldquo;independent.&rdquo;</p><h2 id="a-new-definition-clarity-choice-change">A New Definition: Clarity, Choice, Change</h2><p>True independence is about intentional integration, based on three requirements:</p><ul><li><strong>Clarity:</strong> You can <em>see</em> what you depend on.</li><li><strong>Choice:</strong> You can <em>select</em> your dependencies deliberately.</li><li><strong>Change:</strong> You can <em>shift</em> them when you need to adapt to reality.</li></ul><p>Dependencies you see clearly, chose on purpose and can shift aren&rsquo;t risks. They&rsquo;re the assembly.</p><p>The risky ones are those you can&rsquo;t see, didn&rsquo;t choose and can&rsquo;t change. And those are often the ones created by chasing the wrong definition of independence in the first place.</p><h2 id="the-pain-of-the-wrong-definition">The Pain of the Wrong Definition</h2><p>I worked on an edge connectivity ecosystem for remotely operating oil rigs. The goal was to standardize how software ran at the edge. Authentication, data access, data streaming, etc. All the foundational components every new project needed.</p><p>We built those components once, so other software teams wouldn&rsquo;t have to rebuild them every time.</p><p>It was a strategic bet. I did a lot of the narrative work, high-stakes pitches, executive alignment, the whole thing. The argument was simple: consolidating common parts saves money, reduces waste and lets the company move faster.</p><p>The numbers worked. But the adoption didn&rsquo;t.</p><p>A lot of product teams resisted. Some flat-out refused. The cost-saving argument was easily offset by something they felt more acutely: the fear that being tied to a centralized platform would hold them back later. That when they needed to solve a new problem or make a different strategic choice, this dependency would be in the way.</p><p>They heard the pitch as: <em>Give up your freedom to build, and we&rsquo;ll give you efficiency.</em></p><p>And under the old definition of independence (the negation one), they were right to resist. We were asking them to depend on something they didn&rsquo;t fully control.</p><p>But that&rsquo;s not what was actually happening.</p><p>We weren&rsquo;t asking them to <em>give up</em> independence. We were asking them to <em>redefine</em> it. To stop measuring freedom by what they built themselves, and start measuring it by what they could deliberately depend on. Clearly, on purpose, with the ability to change.</p><p>The pain wasn&rsquo;t the dependency. The pain was the wrong definition.</p><h2 id="what-the-ecosystem-actually-offered">What the Ecosystem Actually Offered</h2><p>Before the platform, every team built authentication, data access and streaming from scratch. They depended on their own budget, their own developers, their own expertise. Their speed, their skill and their security were limited by what each individual team could pull off.</p><p>The result was scattered software. Reinventing the wheel. From a company perspective, it was waste: the same work, done badly, in parallel.</p><p>What the ecosystem offered wasn&rsquo;t fewer dependencies. It was <em>better</em> ones.</p><p>A centralized team with deep expertise. A dependency the company could see, manage and improve. The freedom to shift the underlying technology when something better came along, because the contract was clear and the boundaries were defined.</p><p>The product teams&rsquo; dependencies didn&rsquo;t shrink. They grew. But they became something the company could actually manage.</p><p>A purposeful assembly, with each part chosen.</p><h2 id="the-same-pattern-smaller-scale">The Same Pattern, Smaller Scale</h2><p>The same pattern showed up in our design system work.</p><p>Teams had been forking and falling out of sync, maintaining custom code originally built by an external agency. When the agency engagement ended, we kept the code, but not the expertise. Internal teams were on the hook for something they hadn&rsquo;t built.</p><p>The fix was the same shape as the platform shift: move from custom in-house code to a well-documented third-party framework. We migrated to Progress Kendo UI. The license fee was new but visible. The hidden internal cost, buried in cross-charges and undocumented maintenance, went away.</p><p>We even ran a hybrid model. Kendo UI for most components. Different libraries for charting and mapping if Kendo UI wasn&rsquo;t the best fit. More dependencies, technically. But each one chosen on purpose. Each one we could see and could change if needed.</p><p>Different definition.</p><h2 id="what-independence-actually-looks-like">What Independence Actually Looks Like</h2><p>The question was never <em>how do I become independent?</em> It&rsquo;s <em>what am I depending on, and does it work?</em></p><p>Independence isn&rsquo;t escape from dependence. It&rsquo;s intentional integration. Clear. Chosen. Changeable.</p><p>A purposeful assembly. That&rsquo;s what <em>independent</em> should mean. On purpose. By design.</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">Stop Building Generic Software</h4></div><div class="col-8"><p class="u-fs16 u-mb0"><a target="_blank" href="https://www.telerik.com/blogs/stop-building-generic-software">Stop trying to build</a> what already exists. Start building what sets you apart.</p></div></div></aside>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:ece91e7b-3c59-42b7-935d-f8ca6ba998c3</id>
    <title type="text">Nuxt 4 Notes with AppWrite</title>
    <summary type="text">Build a basic to-do app using Nuxt 4 and Appwrite for hands-on setup and TablesDB experience.</summary>
    <published>2026-06-30T20:22:47Z</published>
    <updated>2026-07-10T23:42:27Z</updated>
    <author>
      <name>Jonathan Gamble </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/nuxt-4-notes-appwrite"/>
    <content type="text"><![CDATA[<p><span class="featured">Build a basic to-do app using Nuxt 4 and Appwrite for hands-on setup and TablesDB experience.</span></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/screenshot_2026-03-14_200837.png?sfvrsn=b6bf0ef8_2" alt="Notes app! Hello Jane. Three notes that look like sticky notes." /></p><p>Nuxt has gone through a few updates since Nuxt 4, and Appwrite has some new ways of handling data with <code>TableDB</code>. Let&rsquo;s build a TODO app!</p><p>⚠️ This app assumes you have basic Nuxt knowledge and can create an Appwrite database.</p><h2 id="tldr">TL;DR</h2><p>We are building Nuxt Notes, a basic to-do app using Nuxt 4 and <a target="_blank" href="https://appwrite.io/">Appwrite</a>. I could not find any good documentation on setting up Appwrite correctly with Nuxt 4, nor on handling the new <code>TablesDB</code> class. This will cover both.</p><h2 id="appwrite">Appwrite</h2><ol><li>Create a new <a target="_blank" href="https://appwrite.io/">Appwrite</a> project. This project is called <code>notes-app</code>.</li><li>For this example, we create a new database called <code>notes</code>. Copy the Database ID for later.</li></ol><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image00.png?sfvrsn=7fff64c5_6" alt="databases - with ID" /></p><ol start="3"><li>Since we are not doing anything complex, the table can also be called <code>notes</code>.</li></ol><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image01.png?sfvrsn=8ec0d8e6_6" alt="Notes. Rows, Columns, Indexes, Activity, Usage, Settings" /></p><ol start="4"><li>We need to configure our tables to have a <code>note</code> string column and an <code>author</code> string column.</li></ol><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image-2.png?sfvrsn=263c6d5_2" alt="note string column and an author string column" /></p><ol start="5"><li>A user should be able to fully CRUD. You can find this in <code>Settings</code> and then <code>Permissions</code>.</li></ol><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image-3.png?sfvrsn=36f30b34_2" alt="Permissions" /></p><h2 id="nuxt-4-setup">Nuxt 4 Setup</h2><p>Now we need to configure Nuxt 4 before we handle the <code>notes</code>.</p><ol><li>Create a new <a target="_blank" href="https://nuxt.com/">Nuxt 4</a> app.</li><li><a target="_blank" href="https://tailwindcss.com/docs/installation/framework-guides/nuxt">Configure Tailwind.</a></li><li>Install Appwrite with <code>npm i appwrite</code>.</li></ol><h3 id="env">ENV</h3><p>First, update <code>nuxt.config.ts</code> to read from <code>.env</code> file.</p><pre class=" language-tsx"><code class="prism  language-tsx">import tailwindcss from "@tailwindcss/vite";

export default defineNuxtConfig({
  compatibilityDate: "2025-07-15",
  devtools: { enabled: true },
  css: ['./app/assets/css/main.css'],
  vite: {
    plugins: [
      tailwindcss(),
    ],
  },
  runtimeConfig: {
    public: {
      appwriteEndpoint: '',
      appwriteProjectId: '',
      appwriteDatabaseId: '',
    },
  },
});
</code></pre><ul><li>Yes, the variables will be empty strings! They automatically get replaced by the ENV data. We use <code>NUXT_PUBLIC_</code> as the public prefix to allow it to be available on the client.</li><li>New words will be capitalized in the config file.</li></ul><p>We need to copy our environmental variables into <code>.env</code> from our Appwrite application.</p><pre class=" language-tsx"><code class="prism  language-tsx">NUXT_PUBLIC_APPWRITE_PROJECT_ID=69168c49003b2c79aafe
NUXT_PUBLIC_APPWRITE_DATABASE_ID=69b5c9ff0024d4feae10
NUXT_PUBLIC_APPWRITE_ENDPOINT=https://nyc.cloud.appwrite.io/v1
</code></pre><ul><li>Your data will be completely different!</li></ul><p>You can find this in project <code>Settings</code>.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image-4.png?sfvrsn=52e5a9c2_2" alt="API credentials" /></p><h3 id="app-file-at-appapp.vue">App File at app/app.vue</h3><pre class=" language-tsx"><code class="prism  language-tsx">&lt;template&gt;
  &lt;main class="flex items-center flex-col gap-5 p-5"&gt;
    &lt;h1 class="text-3xl font-bold text-red-800"&gt;Notes App!&lt;/h1&gt;
    &lt;Auth /&gt;
  &lt;/main&gt;
&lt;/template&gt;
</code></pre><ul><li>We need to display our app, the <code>Auth</code> component will be created in a bit!</li></ul><h3 id="loader-at-appcomponentsloading.vue">Loader at app/components/loading.vue</h3><p>We can create a simple loading spinner.</p><pre class=" language-tsx"><code class="prism  language-tsx">&lt;template&gt;
  &lt;div
    class="animate-spin rounded-full h-10 w-10 border-4 border-b-current border-gray-200"
  &gt;&lt;/div&gt;
&lt;/template&gt;
</code></pre><h2 id="configure-appwrite-at-apppluginsappwrite.ts">Configure Appwrite at app/plugins/appwrite.ts</h2><p>I believe it is bad practice to export data directly and import it in components. Nuxt has <code>plugins</code> for loading data the correct way.</p><pre class=" language-tsx"><code class="prism  language-tsx">import { ID, TablesDB } from 'appwrite'
import { Client, Account, Permission, Role, Query } from 'appwrite'

export default defineNuxtPlugin(() =&gt; {

    const config = useRuntimeConfig()

    const client = new Client()

    const tables = new TablesDB(client)

    client
        .setEndpoint(config.public.appwriteEndpoint)
        .setProject(config.public.appwriteProjectId)

    const account = new Account(client)

    const databaseId = config.public.appwriteDatabaseId

    return {
        provide: {
            ID,
            Permission,
            Role,
            Query,
            client,
            account,
            tables,
            databaseId
        }
    }
})
</code></pre><ul><li>Load the config data with <code>useRuntimeConfig()</code></li><li>Set the <code>client</code>, <code>tables</code> and <code>account</code> classes to be reusable</li><li>Initialize the project with our ENV files with <code>client.setEndpoint().setProject()</code>, and export the <code>databaseId</code></li></ul><h2 id="authentication-composables">Authentication Composables</h2><p>Appwrite does not have an observable like <a target="_blank" href="https://firebase.google.com/">Firebase</a> or <a target="_blank" href="https://supabase.com/">Supabase</a>. You must manually grab the user when you need it with <code>account.get()</code>.</p><h3 id="user-composable-at-appcomposablesuse-user.ts">User Composable at app/composables/use-user.ts</h3><pre class=" language-tsx"><code class="prism  language-tsx">import type { Models } from "appwrite"

type User = Models.User&lt;Models.Preferences&gt;

export const useUser = () =&gt; {

    const { $account } = useNuxtApp()

    const user = useState&lt;{
        data: User | null,
        loading: boolean
    }&gt;('user', () =&gt; ({
        data: null,
        loading: true
    }))

    const getUser = async () =&gt; {
        try {
            user.value.loading = true
            user.value.data = await $account.get()
        } catch (error) {
            user.value.data = null
        } finally {
            user.value.loading = false
        }
        return user
    }

    return {
        user,
        getUser
    }
}
</code></pre><ul><li>Create a reusable <code>user</code> variable, and set it to be sharable from many components with <code>useState</code> instead of <code>ref</code> with the current user state.</li><li>We need to show a loading state while loading.</li><li><code>getUser</code> will have to be called on component mounting.</li></ul><h3 id="auth-composable-at-appcomposableuse-auth.ts">Auth Composable at app/composable/use-auth.ts</h3><pre class=" language-tsx"><code class="prism  language-tsx">import { AppwriteException } from "appwrite"

export const useAuth = () =&gt; {

    const { $account, $ID } = useNuxtApp()

    const { getUser } = useUser()

    const authError = ref&lt;string | null&gt;(null)

    const authForm = ref({
        email: "",
        password: "",
        name: ""
    })

    const login = async () =&gt; {
        
        const { email, password } = authForm.value
        
        try {
            await $account.createEmailPasswordSession({
                email,
                password
            })

            await getUser()

        } catch (error) {
            if (error instanceof AppwriteException) {
                authError.value = error.message
            }
            if (error instanceof Error) {
                authError.value = error.message
            }
            throw error
        }
    }

    const register = async () =&gt; {

        const { email, password, name } = authForm.value

        try {
            await $account.create({
                userId: $ID.unique(),
                email,
                password,
                name
            })

            await login()

        } catch (error) {
            if (error instanceof AppwriteException) {
                authError.value = error.message
            }
            if (error instanceof Error) {
                authError.value = error.message
            }
            throw error
        }

    }

    const logout = async () =&gt; {
        try {
            await $account.deleteSession({
                sessionId: "current"
            })

            await getUser()

        } catch (error) {
            if (error instanceof AppwriteException) {
                authError.value = error.message
            }
            if (error instanceof Error) {
                authError.value = error.message
            }
            throw error
        }
    }

    return {
        register,
        login,
        logout,
        authError,
        authForm
    }
}
</code></pre><ul><li>We must handle <code>login</code>, <code>register</code> and <code>logout</code>. We can also create a shared variable for <code>authError</code> and <code>authForm</code> containing the <code>email</code>, <code>password</code> and <code>name</code> data.</li><li>Most examples don&rsquo;t handle errors. We do here by sending a message to the <code>authError</code> signal.</li><li>We need to check for the correct error types, if there is an error.</li><li>Creating an account does not automatically log in the user.</li></ul><pre class=" language-tsx"><code class="prism  language-tsx">await $account.create({
    userId: $ID.unique(),
    email,
    password,
    name
})
</code></pre><p>You must manually call login afterward.</p><pre class=" language-tsx"><code class="prism  language-tsx">await $account.createEmailPasswordSession({
    email,
    password
})

await getUser()
</code></pre><p>And we call <code>getUser</code> so that our <code>user</code> state signal gets updated reactively.</p><h3 id="auth-component-at-appcomponentsauth.vue">Auth Component at app/components/auth.vue</h3><pre class=" language-tsx"><code class="prism  language-tsx">&lt;script setup lang="ts"&gt;
const { user, getUser } = useUser()
onMounted(getUser)
&lt;/script&gt;

&lt;template&gt;
  &lt;template v-if="user.loading"&gt;
    &lt;Loading /&gt;
  &lt;/template&gt;
  &lt;template v-else-if="user.data"&gt;
    &lt;Logout /&gt;
    &lt;Notes /&gt;
  &lt;/template&gt;
  &lt;template v-else&gt;
    &lt;LoginForm /&gt;
  &lt;/template&gt;
&lt;/template&gt;
</code></pre><ul><li>We call <code>getUser</code> on mount to load the user state.</li><li>We display loading if necessary.</li><li>We show login form if not logged in; otherwise we show logout with our notes component.</li></ul><h3 id="logout-component-at-appcomponentslogout.vue">Logout Component at app/components/logout.vue</h3><pre class=" language-tsx"><code class="prism  language-tsx">&lt;script setup lang="ts"&gt;
const { logout } = useAuth()
const { user } = useUser()
&lt;/script&gt;

&lt;template&gt;
  &lt;h1&gt;Hello {{ user.data?.name }}&lt;/h1&gt;
  &lt;button
    type="button"
    @click="logout"
    class="rounded-lg bg-gray-200 px-4 py-2 text-sm font-medium text-gray-900 transition hover:bg-gray-300"
  &gt;
    Logout
  &lt;/button&gt;
&lt;/template&gt;
</code></pre><ul><li>We display the <code>name</code> using <code>useUser</code>, and create a link to <code>logout</code> using <code>useAuth</code>.</li></ul><h3 id="login-form">Login Form</h3><p>Let&rsquo;s handle registering and logging in!</p><pre class=" language-tsx"><code class="prism  language-tsx">&lt;script setup lang="ts"&gt;
const { login, register, authError, authForm } = useAuth()

const isLogin = ref(true)
&lt;/script&gt;

&lt;template&gt;
  &lt;div
    class="mx-auto max-w-md rounded-xl border border-gray-200 bg-white p-6 shadow-sm"
  &gt;
    &lt;form class="space-y-3"&gt;
      &lt;input
        autocomplete="email"
        type="email"
        placeholder="Email"
        v-model="authForm.email"
        class="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm outline-none transition focus:border-gray-500"
      /&gt;

      &lt;input
        autocomplete="current-password"
        type="password"
        placeholder="Password"
        v-model="authForm.password"
        class="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm outline-none transition focus:border-gray-500"
      /&gt;

      &lt;template v-if="isLogin"&gt;
        &lt;p class="text-sm text-gray-600"&gt;
          Don't have an account?
          &lt;button
            type="button"
            @click="isLogin = false"
            class="text-blue-600 hover:underline"
          &gt;
            Register
          &lt;/button&gt;
        &lt;/p&gt;
      &lt;/template&gt;
      &lt;template v-else&gt;
        &lt;input
          autocomplete="name"
          type="text"
          placeholder="Name"
          v-model="authForm.name"
          class="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm outline-none transition focus:border-gray-500"
        /&gt;
        &lt;p class="text-sm text-gray-600"&gt;
          Already have an account?
          &lt;button
            type="button"
            @click="isLogin = true"
            class="text-blue-600 hover:underline"
          &gt;
            Login
          &lt;/button&gt;
        &lt;/p&gt;
      &lt;/template&gt;

      &lt;template v-if="isLogin"&gt;
        &lt;button
          type="button"
          @click="login"
          class="rounded-lg bg-gray-900 px-4 py-2 text-sm font-medium text-white transition hover:bg-gray-800"
        &gt;
          Login
        &lt;/button&gt;
      &lt;/template&gt;
      &lt;template v-else&gt;
        &lt;button
          type="button"
          @click="register"
          class="rounded-lg bg-gray-200 px-4 py-2 text-sm font-medium text-gray-900 transition hover:bg-gray-300"
        &gt;
          Register
        &lt;/button&gt;
      &lt;/template&gt;
      &lt;template v-if="authError"&gt;
        &lt;p class="mt-2 text-sm text-red-600"&gt;{{ authError }}&lt;/p&gt;
      &lt;/template&gt;
    &lt;/form&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre><ul><li><code>isLogin</code> will toggle login versus registering.</li><li>We don&rsquo;t need to program any functions in our component, as this is all beautifully handled in our <code>useAuth</code> composable!</li><li>We could have created our reactive data directly in this component, but in this case it is automatically synced with the composable.</li></ul><h2 id="notes">Notes</h2><p>We need to add and remove notes.</p><h3 id="notes-composable-at-appcomposablesuse-notes.ts">Notes Composable at app/composables/use-notes.ts</h3><pre class=" language-tsx"><code class="prism  language-tsx">import { AppwriteException } from "appwrite"

type Note = {
    note: string,
    id: string
}

export const useNotes = () =&gt; {

    const notes = useState&lt;{
        data: Note[],
        loading: boolean
    }&gt;('notes', () =&gt; ({
        data: [],
        loading: false
    }))

    const newNote = ref('')

    const noteError = ref&lt;string | null&gt;(null)

    const { user } = useUser()

    const {
        $tables,
        $ID,
        $databaseId,
        $Permission,
        $Role,
        $Query
    } = useNuxtApp()

    const getNotes = async () =&gt; {

        if (!user.value.data) {
            throw new Error('User not authenticated')
        }

        const userId = user.value.data.$id

        try {
            notes.value.loading = true
            const { rows } = await $tables.listRows({
                databaseId: $databaseId,
                tableId: 'notes',
                queries: [
                    $Query.equal('author', userId)
                ]
            })

            notes.value.data = rows.map(row =&gt; ({
                note: row.note,
                id: row.$id
            }))
        } catch (error) {
            if (error instanceof AppwriteException) {
                noteError.value = error.message
            }
            if (error instanceof Error) {
                noteError.value = error.message
            }
            throw error
        } finally {
            notes.value.loading = false
        }
    }

    const addNote = async () =&gt; {

        const note = newNote.value.trim()

        const userData = user.value?.data

        if (!userData) {
            throw new Error('User not authenticated')
        }

        const userId = userData.$id

        // optimistically add note

        const rowId = $ID.unique()

        notes.value.data.push({
            note,
            id: rowId
        })

        newNote.value = ''

        try {
            await $tables.createRow({
                databaseId: $databaseId,
                tableId: 'notes',
                rowId,
                data: {
                    note,
                    author: userId
                },
                permissions: [
                    $Permission.read($Role.user(userId)),
                    $Permission.update($Role.user(userId)),
                    $Permission.delete($Role.user(userId))
                ]
            })

        } catch (error) {

            // remove optimistically added note
            notes.value.data = notes.value.data.filter(n =&gt; n.note !== note)

            newNote.value = note

            if (error instanceof AppwriteException) {
                noteError.value = error.message
            }
            if (error instanceof Error) {
                noteError.value = error.message
            }
            throw error
        }
    }

    const removeNote = async (id: string) =&gt; {

        // optimistically remove note
        const index = notes.value.data.findIndex(n =&gt; n.id === id)

        if (index === -1) {
            noteError.value = 'Note not found'
            return
        }

        const note = notes.value.data[index]!

        notes.value.data.splice(index, 1)

        try {
            await $tables.deleteRow({
                databaseId: $databaseId,
                tableId: 'notes',
                rowId: id
            })
        } catch (error: unknown) {
            // re-add optimistically removed note
            notes.value.data.splice(index, 0, note)
            if (error instanceof AppwriteException) {
                noteError.value = error.message
            }
            if (error instanceof Error) {
                noteError.value = error.message
            }
            throw error
        }
    }

    const resetNotes = () =&gt; {
        notes.value = {
            data: [],
            loading: false
        }
    }

    return {
        addNote,
        removeNote,
        notes,
        noteError,
        getNotes,
        resetNotes,
        newNote
    }
}
</code></pre><ul><li>We <code>getNotes</code> to display them, <code>addNotes</code> from the form, and <code>removeNotes</code> from the button.</li><li>There should be no case where a user can see notes without being logged in, but we handle that anyway.</li></ul><pre class=" language-tsx"><code class="prism  language-tsx">const getNotes = async () =&gt; {

    if (!user.value.data) {
        throw new Error('User not authenticated')
    }
    ...
</code></pre><ul><li>We optimistically add notes to our <code>notes</code> signal, and if it fails, we remove them. This is what Firebase does automatically. We also optimistically remove them, and if it fails, add them back. This will create an extremely fast UI!</li></ul><pre class=" language-tsx"><code class="prism  language-tsx">notes.value.data.push({
    note,
    id: rowId
})

...

// optimistically remove note
const index = notes.value.data.findIndex(n =&gt; n.id === id)

if (index === -1) {
    noteError.value = 'Note not found'
    return
}

const note = notes.value.data[index]!
</code></pre><ul><li>Appwrite handles permissions on create by the user that created them.</li></ul><pre class=" language-tsx"><code class="prism  language-tsx">await $tables.createRow({
    databaseId: $databaseId,
    tableId: 'notes',
    rowId,
    data: {
        note,
        author: userId
    },
    permissions: [
        $Permission.read($Role.user(userId)),
        $Permission.update($Role.user(userId)),
        $Permission.delete($Role.user(userId))
    ]
})
</code></pre><ul><li>We also need the <code>database id</code> when we add a new <code>note</code>, and we want to match it with the user <code>author</code> it belongs to.</li><li>The <code>Role.user(userId)</code> gets created by the logged in <code>userId</code>.</li><li>Removing is simple:</li></ul><pre class=" language-tsx"><code class="prism  language-tsx">await $tables.deleteRow({
    databaseId: $databaseId,
    tableId: 'notes',
    rowId: id
})
</code></pre><ul><li>Fetching requires a filter of the <code>userId</code>:</li></ul><pre class=" language-tsx"><code class="prism  language-tsx">const { rows } = await $tables.listRows({
    databaseId: $databaseId,
    tableId: 'notes',
    queries: [
        $Query.equal('author', userId)
    ]
})
</code></pre><ul><li><code>Query.equal</code> covers our <code>author</code> column filter.</li></ul><h3 id="add-a-note-at-appcomponentsadd-note.vue">Add a Note at app/components/add-note.vue</h3><pre class=" language-tsx"><code class="prism  language-tsx">&lt;script lang="ts" setup&gt;
const { addNote, noteError, newNote } = useNotes()
&lt;/script&gt;

&lt;template&gt;
  &lt;form class="mx-auto flex max-w-md gap-2"&gt;
    &lt;textarea
      autocomplete="note"
      type="text"
      name="note"
      v-model="newNote"
      placeholder="Enter a note"
      class="flex-1 rounded-md border border-gray-300 px-3 py-2 text-sm outline-none focus:border-gray-500"
    /&gt;
    &lt;button
      type="submit"
      @click.prevent="addNote"
      class="rounded-md bg-black px-4 py-2 text-sm font-medium text-white hover:bg-gray-800"
    &gt;
      Add Note
    &lt;/button&gt;
  &lt;/form&gt;

  &lt;p v-if="noteError" class="mx-auto mt-2 max-w-md text-sm text-red-600"&gt;
    {{ noteError }}
  &lt;/p&gt;
&lt;/template&gt;
</code></pre><ul><li>Putting things in our composables makes our templates extremely clean. Again, we handle our errors with <code>noteError</code>.</li></ul><h3 id="notes-component-at-appcomponentsnotes.vue">Notes Component at app/components/notes.vue</h3><p>And we display our notes to each user.</p><pre class=" language-tsx"><code class="prism  language-tsx">&lt;script lang="ts" setup&gt;
const { notes, removeNote, resetNotes, getNotes } = useNotes()

onMounted(getNotes)
onUnmounted(resetNotes)
&lt;/script&gt;

&lt;template&gt;
  &lt;p class="mb-4 text-center text-lg font-semibold text-gray-800"&gt;Notes&lt;/p&gt;
  &lt;template v-if="notes.loading"&gt;
    &lt;Loading /&gt;
  &lt;/template&gt;
  &lt;template v-else-if="notes.data.length"&gt;
    &lt;ul
      class="mx-auto mb-6 grid max-w-4xl grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3"
    &gt;
      &lt;li
        v-for="note in notes.data"
        :key="note.id"
        class="relative min-h-45 -rotate-1 rounded-sm border border-yellow-200 bg-yellow-200 p-4 shadow-md"
      &gt;
        &lt;div
          class="absolute left-1/2 top-0 h-5 w-16 -translate-x-1/2 -translate-y-1/2 -rotate-3 bg-yellow-100/80 shadow-sm"
        /&gt;

        &lt;p class="pb-12 text-sm leading-6 text-gray-800"&gt;
          {{ note.note }}
        &lt;/p&gt;

        &lt;button
          type="button"
          class="absolute bottom-3 right-3 not-[]:px-3 py-1 hover:opacity-50"
          @click="removeNote(note.id)"
        &gt;
          ️
        &lt;/button&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/template&gt;
  &lt;template v-else&gt;
    &lt;p class="mb-6 text-center text-gray-500"&gt;No notes yet. Add one below!&lt;/p&gt;
  &lt;/template&gt;
  &lt;AddNote /&gt;
&lt;/template&gt;
</code></pre><ul><li>Notice we retrieve our notes on mounting, and we reset our notes signal on unmounting.</li><li>Notes also need a loading state since they are a separate async function.</li></ul><h2 id="app-flow">App Flow</h2><p>We can login or register, and each user has their own todos!</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image-5.png?sfvrsn=9f012a0d_2" alt="notes app login" /></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image-6.png?sfvrsn=d2d17d97_2" alt="user already exists" /></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image-7.png?sfvrsn=27daa395_2" alt="Hello Jane! No notes yet. Add one below!" /></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image-8.png?sfvrsn=b372e3b8_2" alt="four notes" /></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/chrome_d9qpokriur.gif?sfvrsn=ee6b8406_2" alt="Demo of adding and deleting notes" /></p><p><strong>Repo:</strong> <a target="_blank" href="https://github.com/jdgamble555/nuxt-notes-appwrite">GitHub</a></p><p> I don&rsquo;t have a demo because the free Appwrite project will pause after a certain time, but this demo should be pretty easy to clone.</p><p>Happy coding!</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">Nuxt 4 Server Routes vs. Fetch Composables</h4></div><div class="col-8"><p class="u-fs16 u-mb0">See a Nuxt app load data from the server in a Server Component and using useFetch to see <a target="_blank" href="https://www.telerik.com/blogs/nuxt-4-server-routes-vs-fetch-composables">how Server Components and fetch mechanisms compare</a>.</p></div></div></aside>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:25764796-2937-4908-aea5-7d0a72c05de6</id>
    <title type="text">Choosing the Right Telerik UI for Blazor Chart</title>
    <summary type="text">Which type of chart is best for your data set? Explore the different types of Blazor charts and get a guide of which to use in certain use cases.</summary>
    <published>2026-06-30T16:57:43Z</published>
    <updated>2026-07-10T23:42:27Z</updated>
    <author>
      <name>Héctor Pérez </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/choosing-right-telerik-ui-blazor-chart"/>
    <content type="text"><![CDATA[<p><span class="featured">Which type of chart is best for your data set? Explore the different types of Blazor charts and get a guide of which to use in certain use cases.</span></p><p>In data-driven applications, it is common to want to display information dynamically and visually. However, there are times when we have doubts about which type of chart to use in our applications.</p><p>Choosing the wrong type of chart can cause users to become confused or even distort the information by displaying it incompletely or with a layout that doesn&rsquo;t make much sense.</p><p>That is why this article is a roundup of the types of charts available in the Progress Telerik <a target="_blank" href="https://www.telerik.com/blazor-ui">UI suite for Blazor</a> and when to use each. Let&rsquo;s get to it!</p><h2 id="chart-types-in-telerik-ui-for-blazor">Chart Types in Telerik UI for Blazor</h2><p>Let&rsquo;s analyze the different types of <a target="_blank" href="https://www.telerik.com/blazor-ui/documentation/components/chart/overview">charts available in Telerik UI for Blazor</a>, as well as when to use them.</p><h3 id="column-chart">Column Chart</h3><p>The first type of chart, column, is perhaps the simplest. With this chart we can display vertical bars in which the height represents the value of each category. It&rsquo;s a quite versatile chart type, which is why it&rsquo;s very common to see it in applications and elsewhere. The chart looks like the following:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/simple-column-chart.png?sfvrsn=2ad90540_2" alt="Simple column chart" /></p><p>This type of chart is useful when we want to compare values across categories, show rankings or classifications, and visualize data where order does matter.</p><h3 id="bar-chart">Bar Chart</h3><p>The bar chart is the equivalent of the column chart but in a horizontal format. In the Telerik component <code>ChartSeriesType.Bar</code> is used and the category axis is on the vertical axis instead of horizontal:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/simple-bar-chart.png?sfvrsn=2e966c33_2" alt="Simple bar chart showing categories and values." /></p><p>This chart can be used when category names are long and you need more space to display them, when you want to show a horizontal comparison between values, and when you want to emphasize the difference in values between categories.</p><h3 id="line-chart">Line Chart</h3><p>The line chart displays a graph with connected points, which makes this chart ideal for showing trends over time. In the Telerik component it supports normal, step and smooth lines:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/simple-line-chart.png?sfvrsn=4c604b1_2" alt="Simple line chart showing an upward trend" /></p><p>This chart is suitable when we want to visualize temporal trends, compare different evolutions within the same period and when continuity between data points is relevant.</p><h3 id="area-chart">Area Chart</h3><p>This type of chart is similar to the line chart, with the difference that the space beneath the lines is filled with a semi-transparent color. This gives greater emphasis to the volume or magnitude of the data. In the Telerik component we can control the opacity using the <code>Opacity</code> property.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/area-chart-simple.png?sfvrsn=5e3dca17_2" alt="Simple area chart showing rising values over time" /></p><p>You can use this chart when you want to emphasize the volume of the data, their trend or when you want to show how different series overlap.</p><h3 id="pie-chart">Pie Chart</h3><p>The pie chart displays a circle divided into proportional slices for each value specified in the category. It only supports a single series, which makes it an ideal chart for showing the composition of a whole:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/simple-pie-chart.png?sfvrsn=56a76ea0_2" alt="Simple pie chart showing proportional data distribution" /></p><p>Some examples of when to use this type of chart are when you want to show a percentage distribution of data, while being mindful of the maximum number of slices so as not to overcrowd the chart. Likewise, when you want users to quickly understand portions of a whole and when you require the values to add up to 100%.</p><h3 id="donut-chart">Donut Chart</h3><p>This type of chart is similar to a pie chart but with a hole in the center. This hole can be used to display a highlighted data point or, as the Progress Telerik team has done, allow multiple series to be shown:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/donut-chart-simple.png?sfvrsn=89334033_2" alt="Simple donut chart with four colored segments" /></p><p>This chart is recommended for showing, in addition to the pie-chart scenarios, hierarchical relationships between data sets.</p><h3 id="scatter-chart">Scatter Chart</h3><p>The scatter chart displays a series of points defined by the <strong>x</strong> and <strong>y</strong> axes, with these being numeric data:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/scatter-plot-basic.png?sfvrsn=f64a9932_2" alt="Scatter plot showing correlated data points" /></p><p>This type of chart is ideal when you want to show a correlation between two numeric variables, such as the relationship between users connected in an application and a website&rsquo;s load time. It is also useful for identifying patterns, clusters, scientific data, among others.</p><h3 id="bubble-chart">Bubble Chart</h3><p>This chart is similar to the scatter chart in how it works, but adds a third dimension, which is the size of the bubble:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/simple-bubble-chart.png?sfvrsn=34686cbe_2" alt="Simple bubble chart showing values by size" /></p><p>The third dimension is useful for comparing entities with multiple metrics simultaneously.</p><h3 id="scatter-line-chart">Scatter Line Chart</h3><p>The scatter line chart is similar to the scatter chart, except that in this case the points are connected by lines:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/scatter-line-plot.png?sfvrsn=86d3bc9b_2" alt="Scatter plot with connecting line showing data relationship" /></p><p>This chart is convenient to use when you want to show the relationship between two variables while maintaining continuity in the data or trend.</p><h3 id="candlestick-chart">Candlestick Chart</h3><p>This candlestick-style chart is widely used in the financial sector, as it allows showing four values for a period: open, close, high and low. If we are talking about stocks in the securities market, the body of the candle represents the price from open to close, while the wicks, which are the thin lines above and below, show the period&rsquo;s high and low:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/candlestick-chart.png?sfvrsn=a9d98305_2" alt="Candlestick chart showing market price movements" /></p><p>This chart is suitable for showing financial movements or when you want to identify trading patterns.</p><h3 id="ohlc-chart-open-high-low-close">OHLC Chart (Open-High-Low-Close)</h3><p>This chart shows the same four values as the candlestick chart, but instead of using candle bodies, it uses horizontal marks. In this chart the horizontal values represent the open and close, while the lower and upper extremes show the maximum and minimum:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/ohlc-candlestick-chart.png?sfvrsn=3fafa6ef_2" alt="Candlestick OHLC chart" /></p><p>The use cases for this chart are the same as for the candlestick chart, but when you want a cleaner visualization. It is also ideal when you want to show many time periods, in which a candlestick chart would overlap the values.</p><h3 id="heatmap-chart">Heatmap Chart</h3><p>The heatmap displays a grid where color intensity represents the magnitude of a value across two dimensions:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/heatmap-chart-color-grid.png?sfvrsn=2f853608_2" alt="Heatmap showing color-coded intensity across a grid" /></p><p>If you are a software developer, you will surely recognize the image above, since GitHub shows a similar chart to display the commits you have made on an account. This demonstrates that the chart is ideal for showing an activity density in two dimensions and when you want to show behavior patterns across intersecting categories.</p><h3 id="radar-line-chart">Radar Line Chart</h3><p>This chart starts from a common center from which several axes radiate. Each axis represents a specific value, which are then connected to form a closed shape:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/radar-line-chart.png?sfvrsn=2ef60c49_2" alt="Radar line chart comparing multiple variables" /></p><p>It is very useful when you want to make profile comparisons, such as variables between LLM models or when you want to make before/after comparisons.</p><h3 id="radar-area-chart">Radar Area Chart</h3><p>This radar area chart is similar to the radar line chart, with the difference that the space of the formed shape is filled with a color:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/radar-area-chart-filled.png?sfvrsn=364cf4ed_2" alt="Filled radar area chart showing multivariate data" /></p><p>This chart works well to understand how different profiles overlap on the chart quickly.</p><h3 id="radar-column-chart">Radar Column Chart</h3><p>The radar column chart follows the same principle as the radar line and radar area charts, with the difference that it shows diagonal bars extending from the center:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/radar-column-chart.png?sfvrsn=5607c18f_2" alt="Radar column chart for comparison" /></p><p>By showing bars instead of connecting points, this chart is excellent for comparing individual values across categories and when an overlap in the radar area could make reading values difficult.</p><h3 id="range-area-chart">Range Area Chart</h3><p>The range area chart shows an area defined between two continuous lines defining the range between a minimum and a maximum value, similar to the area chart but not starting from zero:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/range-area-chart.png?sfvrsn=1a0018c5_2" alt="Range area chart showing high and low values." /></p><p>By displaying ranges, it is ideal in scenarios such as temperature ranges, error margins and when you need to emphasize a difference between continuous sequences of values.</p><h3 id="range-bar-chart">Range Bar Chart</h3><p>This chart lets you display ranges of values over a period of time using horizontal bars, whose position and length vary according to a from value and a to value:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/range-bar-chart.png?sfvrsn=d0c7eb72_2" alt="Horizontal range bar chart showing start and end values" /></p><p>This chart can help you show time ranges or durations, or compare ranges between categories or groups.</p><h3 id="range-column-chart">Range Column Chart</h3><p>It is the vertical version of the range bar chart. In this chart vertical bars are displayed, which vary according to the from and to values:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/range-column-chart.png?sfvrsn=13016741_2" alt="Range column chart showing min and max values" /></p><p>This chart could be useful to show ranges of scores between periods or when you need to emphasize both the minimum and the maximum of each category.</p><h3 id="waterfall-chart">Waterfall Chart</h3><p>This chart is based on a series of bars that show a cumulative value of sequential positive and negative values. Each bar starts where the previous one ended, which allows you to see the value&rsquo;s behavior after a period. In the Telerik component it is also possible to display columns with total or partial values:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/waterfall-chart-simple.png?sfvrsn=5b498a9d_2" alt="Waterfall chart showing sequential positive and negative values" /></p><p>Use cases for this chart include when you need to analyze cash flow over months, for budget and profitability analysis, among others.</p><h3 id="sankey-chart">Sankey Chart</h3><p>This Telerik component <code>TelerikSankey</code> displays a set of entities and links to represent the flow between them. In addition, the thickness of each link shows the value, allowing users to easily see the entity-to-value flow:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/sankey-diagram-flows.png?sfvrsn=be7afe80_2" alt="Sankey diagram showing flows between categories" /></p><p>Because of its flexibility, the Sankey chart is ideal for analyzing traffic distributions, breaking down budgets or redistributing resources.</p><h3 id="stock-chart">Stock Chart</h3><p>To use a stock chart, you should use the <code>TelerikStockChart</code> component, which is part of the Telerik UI for Blazor suite. This component is specifically designed for financial time series data. It supports types we&rsquo;ve already covered such as candlestick and OHLC, with the difference that it includes a navigator to select a specific time period:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/stock-market-line-chart.gif?sfvrsn=33fc642e_2" alt="Stock chart showing stock market price movements" /></p><p>This component is useful when you need to navigate time periods in financial data or to create trading dashboards or investment analysis.</p><h3 id="trendline-chart">Trendline Chart</h3><p>The last chart type we&rsquo;ll analyze is the trendline type. This chart isn&rsquo;t really a chart type where you define its own data; rather, it takes the data from an existing chart to reveal the trend of the data. The component supports several trend types: linear, average, exponential, logarithmic, among others:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/trendline-chart-simple.png?sfvrsn=68161b2c_2" alt="Simple trendline chart showing upward data trend" /></p><p>Some use cases for this chart type include revealing the overall direction of the data, smoothing fluctuations, performing forecasts, as well as conducting statistical analyses and validating patterns over time.</p><h3 id="decision-tree-for-selecting-the-best-chart">Decision Tree for Selecting the Best Chart</h3><p>After having analyzed the different types of charts that we can find in the Telerik UI for Blazor suite, I want to leave you a decision list that can help you select the best chart for your use case:</p><p><strong>Comparison &amp; Trends</strong><br />- If there is time or continuity -&gt; Use a line, area or scatter line chart<br />- If there are simple categories -&gt; Use a column or bar chart<br />- If there are long category names -&gt; Use a bar chart<br />- If you want to show underlying trends -&gt; Add a trendline</p><p><strong>Composition (Parts of a Whole)</strong><br />- For a single series -&gt; Use a pie or donut chart<br />- For multiple series -&gt; Use a donut chart<br />- For flows between domains -&gt; Use a Sankey diagram</p><p><strong>Relationships &amp; Distribution</strong><br />- With 2 variables -&gt; Use a scatter plot<br />- With 3 variables -&gt; Use a bubble chart<br />- For 2D density -&gt; Use a heatmap<br />- For multidimensional profiles -&gt; Use a radar chart (area, column or line)</p><p><strong>Ranges &amp; Cumulative Changes</strong><br />- To show the effect of changes -&gt; Use a waterfall chart<br />- For continuous ranges -&gt; Use a range area chart<br />- For time durations -&gt; Use a range bar chart<br />- For vertical ranges -&gt; Use a range column chart</p><p><strong>Specialized Data</strong><br />- For financial/price movement -&gt; Use a candlestick or stock chart</p><p>This list should help you make a better decision about when to use each type of chart.</p><h2 id="conclusion">Conclusion</h2><p>Throughout this article, we have taken a tour of the different types of charts that we can find in the Telerik suite for Blazor. This was aimed at understanding the structure of each one, how it looks and which are the best scenarios for their use. After this information, it&rsquo;s your turn to present your users&rsquo; data in different ways, always keeping in mind that their interpretation should be as simple as possible.</p><p>Ready to experiment with all these chart types? Telerik UI for Blazor comes with a free 30-day trial:</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:1bd8e293-fa30-4fab-803e-f42e54e29d42</id>
    <title type="text">Check Out These Amazing Projects from the Progress x GitNation Hackathon!</title>
    <summary type="text">We hosted a hackathon in partnership with GitNation, and the response blew us away. In just 48 hours, we got over 30 finished projects! Check out our winners and some of our favorites.</summary>
    <published>2026-06-29T16:35:30Z</published>
    <updated>2026-07-10T23:42:27Z</updated>
    <author>
      <name>Kathryn Grayson Nanz </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/check-out-amazing-projects-progress-gitnation-hackathon"/>
    <content type="text"><![CDATA[<p><span class="featured">Our Progress x GitNation hackathon at React Summit and JSNation netted 30+ projects that blew us away. Check out our winners and some of our favorites.</span></p><p>A few weeks ago, the Progress team headed to Amsterdam for <a target="_blank" href="https://reactsummit.com/">React Summit</a> and <a target="_blank" href="https://jsnation.com/">JSNation</a>: two of the back-to-back biggest events on the JavaScript calendar. </p><p>Between the packed schedule, booth conversations, social events and time hanging out with a few hundred of your closest developer friends, it was a seriously week. Not to mention, our team finally got to spend some time together in-person&mdash;something that doesn&rsquo;t happen very often when you&rsquo;re scattered across the globe! Although we all left feeling exhausted (and at least in my case, wildly jet-lagged), it was absolutely worth the trip.</p><p><img sf-image-responsive="true" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/.net-maui-aiprompt/1781519496198.jpg?sfvrsn=819290e8_2" height="575" style="max-width:100%;height:auto;" title="1781519496198" width="1280" alt="Kiril, on stage at React Summit. " sf-size="105038" /></p><p>Our own Kiril Peyanski took the React Summit stage to deliver a talk on generative frontend, exploring a new paradigm where LLMs generate the logic that maps data to UI using React Server Components and Server Functions to make interfaces that adapt to the user. And when I tell you the room was packed, I mean <em>literally</em> standing room only and overflowing out the door!</p><p><img sf-image-responsive="true" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/.net-maui-aiprompt/1781519492695.jpg?sfvrsn=f86ecc35_2" height="963" style="max-width:100%;height:auto;" title="1781519492695" width="1280" alt="Kiril&#39;s talk, overflowing with attendees " sf-size="204170" /></p><p>As part of the conference, we also hosted a hackathon in partnership with <a target="_blank" href="https://gitnation.com/">GitNation</a>, challenging attendees to build something that makes tech conferences better. We left the specifics up to our hackers. It could mean better for attendees, better for speakers, better for organizers or something else entirely. We wanted to see how creative folks would get, and the response blew us away. The hackathon lasted just 48 hours, and we had over 30 finished projects!</p><p>After judging (which, let me tell you, was a real challenge), three projects stood out from the crowd:</p><p><strong>Our grand prize winners, <a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/502">HALLWAY</a>:</strong> The team behind HALLWAY built a mobile-first app that turns the chaos of a conference day into a personalized, connected flow. Answer a few quick questions, and it builds your schedule, fills your free gaps with curated intros to the right people, and places you in a small group for the evening. </p><p><strong>Our first runner-up, <a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/593">Conf Pilot</a>:</strong> Conf Pilot is an MCP server that brings live conference schedules directly into AI chat. Ask "what&rsquo;s next?" and instead of a wall of text, you get a fully interactive, themed widget with track filters, live countdown timers and calendar links&mdash;all without leaving your AI assistant. One of the first projects to use the new MCP Apps structured content pattern, and a seriously impressive build for a one-person submission! </p><p><strong>Our second runner-up, <a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/524">Stuck Stack</a>:</strong> Stuck Stack turns the conference into a live help marketplace. Post what you&rsquo;re blocked on, find someone nearby who can help you in five minutes, and watch blockers move across a live board from Open &rarr; Matched &rarr; Solved. Organizers get a real-time dashboard that can even detect when enough attendees are stuck on the same thing and suggest a pop-up help clinic on the spot. Clever, useful and beautifully designed.</p><p><img sf-image-responsive="true" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/.net-maui-aiprompt/1781519491888.jpg?sfvrsn=6fdf2f90_2" height="575" style="max-width:100%;height:auto;" title="1781519491888" width="1280" alt="The Progress team on stage with the overall winners, team HALLWAY " sf-size="113685" /></p><p>However, we couldn&rsquo;t give prizes to everyone&mdash;as much as we wished we could! When I tell you the judging was a challenge, it&rsquo;s because we had other submissions like these that were so, <em>so</em> impressive. While these unfortunately didn&rsquo;t end up placing, we do want to make sure they get their time in the sun as well, so you can also appreciate their incredible work! </p><p><strong><a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/579">The Hallway</a></strong> took a new swing at the age-old problem of networking. Your AI agent walks into the conference before you do, negotiates with other attendees&rsquo; agents to find the right matches and only reveals identities once both humans consent. </p><p><strong><a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/592">Unison</a></strong> tackled something nobody else touched&mdash;language barriers. It dubs conference talks in real-time, letting speakers present in one language while every attendee hears it in their own, with no headsets and about a three-second lag. Two-way, too: attendees can ask questions in their language and the speaker receives them in theirs.</p><p><strong><a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/595">CrowdShift</a></strong> flipped the speaker experience on its head. Speakers normally prepare blind, with no idea who&rsquo;s actually in the room. CrowdShift pulls registration data and builds a continuously updated audience brief, so a speaker can see that their crowd shifted from 65% senior to 55% junior and adapt their talk in real time.</p><p><strong><a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/588">ConferenceCast</a></strong> treated a multi-track conference like a TV broadcast: every room is a channel, and you get a personalized program guide with AI match scores, live session cards, countdown timers and a control-room dashboard for organizers to track what&rsquo;s working in real time.</p><p><strong><a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/581">FireRaven Conference Hub </a></strong>went after a bigger problem: conference discovery is basically guesswork. Their platform gives speakers portable reputation profiles and lets attendees rate events across meaningful dimensions&mdash;expertise, clarity, practical impact and energy.</p><p><strong><a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/573">Nexo</a></strong> kept it focused: tell it your role, goals and interests, and it builds you a focused conference plan with a clear explanation for every recommendation. Sometimes, the best solutions are the simple ones.</p><p><strong><a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/580">Stage Deployer</a></strong> changes how you give talks. It lets speakers create small audience apps from a simple text prompt. Just type an idea, wait about two minutes, then share a QR code for the audience to scan. The interaction results appear live on the big screen as charts, rankings or word clouds.</p><p>We highly encourage you to <a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects">check out all the submissions in the project gallery </a>and see the incredible variety of things people built with Telerik and Kendo UI components from Progress Software.</p><p><img sf-image-responsive="true" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/.net-maui-aiprompt/img_4975.jpeg?sfvrsn=f5e0c414_2" height="786" style="max-width:100%;height:auto;" title="IMG_4975" width="1179" alt="The Progress team in front of the booth at JS Nation / React SUmmit " sf-size="271594" /></p><p>Amsterdam delivered on all fronts: the venue was great, the crowd was friendly and the whole experience reminded us just how great it is to be able to spend time together with a bunch of folks all excited to geek out about the same stuff.</p><p><em>Huge</em> congrats to all three of our hackathon winning teams, and a massive well done to every single person who submitted. More than 30 projects in a couple of days is no joke! We had a fantastic time, and we&rsquo;re already looking forward to the next one.</p><hr /><h3>Ready to build your next React app?</h3><p><a href="https://www.telerik.com/kendo-react-ui" class="Btn" target="_blank">Explore KendoReact</a></p>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:9fd87dc0-365e-47d0-8606-b091b8bd9ccb</id>
    <title type="text">Best Practices for Exceptions in ASP.NET Core</title>
    <summary type="text">Exceptions are a common approach to dealing with unexpected situations. But are they truly necessary? Let’s see some best practices for using them in ASP.NET Core.</summary>
    <published>2026-06-29T13:01:51Z</published>
    <updated>2026-07-10T23:42:27Z</updated>
    <author>
      <name>Assis Zang </name>
    </author>
    <link rel="alternate" href="https://www.telerik.com/blogs/best-practices-exceptions-aspnet-core"/>
    <content type="text"><![CDATA[<p><span class="featured">Exceptions are a common approach to dealing with unexpected situations. But are they truly necessary? Let&rsquo;s see some best practices for using them in ASP.NET Core.</span></p><p>Exceptions have been part of the .NET ecosystem since the earliest versions of the .NET Framework. Today, with the platform&rsquo;s continuous evolution, their use is simpler and more integrated than ever. The problem, however, arises when they are used inappropriately or imprecisely.</p><p>In this post, we will explore in which situations the use of exceptions is truly recommended and when more appropriate alternatives should be considered. Furthermore, we will see in practice some of the most modern features available in ASP.NET Core for implementing exception handling aligned with best practices.</p><h2 id="-what-are-exceptions-in-the-context-of-asp.net-core"> What Are Exceptions in the Context of ASP.NET Core?</h2><p>In ASP.NET Core, exceptions are objects that represent unexpected events that occur during program execution and interrupt its normal flow. Common examples of flow interruption include null reference errors, invalid user input, and database connection problems.</p><p>In practice, when an exception is thrown, the .NET runtime starts looking for somewhere that knows how to handle it, typically a <code>try/catch</code> statement, as shown in the example below:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">try</span>
<span class="token punctuation">{</span>
    <span class="token keyword">var</span> result <span class="token operator">=</span> <span class="token number">10</span> <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">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">throw</span> <span class="token keyword">new</span> <span class="token class-name">Exception</span><span class="token punctuation">(</span><span class="token string">"Error: "</span> <span class="token operator">+</span> ex<span class="token punctuation">.</span>Message<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>If this exception is not handled, it returns to the beginning of the execution and eventually reaches the ASP.NET Core pipeline, resulting in an HTTP error, usually a <code>500 - Internal Server Error</code>.</p><h2 id="-when-should-exceptions-be-avoided"> When Should Exceptions Be Avoided?</h2><p>One of the most common mistakes in backend applications is using exceptions for expected situations. If code already expects something to happen, then it&rsquo;s not exceptional, it&rsquo;s predictable.</p><p>The principle of exceptions is to <strong>reserve exceptions for unpredictable situations</strong>.</p><p>A common example of a situation where exceptions should be avoided is for input data validation. Data validation should never use exceptions as a rule. Note the example below:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span>BankAccountNumber<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Exception</span><span class="token punctuation">(</span><span class="token string">"BankAccountNumber is required"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>The problem here is that the system expects the client to send a user with invalid data. In other words, this is part of the normal flow, not an exception. In this case, the correct approach would be to treat this as data validation and simply return a <code>400 Bad Request</code>:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span>BankAccountNumber<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">return</span> Results<span class="token punctuation">.</span><span class="token function">BadRequest</span><span class="token punctuation">(</span><span class="token string">"BankAccountNumber is required"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><h2 id="-when-does-using-exceptions-make-sense"> When Does Using Exceptions Make Sense?</h2><p>If exceptions shouldn&rsquo;t be used in the normal flow, then when do they make sense? In backend applications like ASP.NET Core, <strong>exceptions should be used when something truly unexpected happens and the application cannot continue safely or should not continue at all</strong>.</p><p>Below, we&rsquo;ll look at practical scenarios where exceptions actually make sense.</p><h3 id="-infrastructure-failures"> Infrastructure Failures</h3><p>This is a very common scenario. If the database fails here, it&rsquo;s not possible to proceed normally, meaning it&rsquo;s an exception:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">try</span>
<span class="token punctuation">{</span>
    <span class="token keyword">var</span> user <span class="token operator">=</span> <span class="token keyword">await</span> dbContext<span class="token punctuation">.</span>Users<span class="token punctuation">.</span><span class="token function">FindAsync</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> Results<span class="token punctuation">.</span><span class="token function">Ok</span><span class="token punctuation">(</span>user<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">return</span> Results<span class="token punctuation">.</span><span class="token function">InternalServerError</span><span class="token punctuation">(</span>$<span class="token string">"Error retrieving user. Error details: {ex.Message}"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><h3 id="⚠️-impossible-or-inconsistent-states">⚠️ Impossible or Inconsistent States</h3><p>Despite frontend and backend validations, inconsistent states can reach the application core. If this happens, something is certainly wrong, and this corrupted state cannot be saved to the database or continue its path. In this case, an exception must be generated:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">if</span> <span class="token punctuation">(</span>BankAccountNumber<span class="token punctuation">.</span>Length <span class="token operator">&lt;</span> <span class="token number">8</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">InvalidOperationException</span><span class="token punctuation">(</span><span class="token string">"The bank account number must have at least 8 digits at this point"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>If the system logic guarantees that <code>BankAccountNumber</code> will always have at least 8 characters at this point, then this indicates a bug, data inconsistency or even a flow error, and the exception is the last resort to prevent an inconsistent state at this stage of the process.</p><h3 id="-dependency-on-external-services"> Dependency on External Services</h3><p>If the external service is mandatory for the flow and the absence of data completely prevents correct processing, then you are dealing with a real error and the exception represents a technical problem.</p><p>In this case, it is correct to throw an exception because the process cannot continue with inconsistent data. Furthermore, it is important to clarify that the error occurred in the integration between the services, as demonstrated in the example below:</p><pre class=" language-csharp"><code class="prism  language-csharp">   <span class="token keyword">var</span> customer <span class="token operator">=</span> <span class="token keyword">await</span> externalService<span class="token punctuation">.</span><span class="token function">GetCustomerAsync</span><span class="token punctuation">(</span>customerId<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>customer <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">throw</span> <span class="token keyword">new</span> <span class="token class-name">InvalidOperationException</span><span class="token punctuation">(</span><span class="token string">"Unable to retrieve customer data from the external service: CustomerService"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
</code></pre><h2 id="result-pattern-as-an-alternative">Result Pattern as an Alternative</h2><p>If exceptions shouldn&rsquo;t be used for normal flow, the question arises: what would be a good alternative to represent expected errors?</p><p>One of the most widely used alternatives today is the Result Pattern. The Result Pattern is a design pattern used to manage execution flow and errors, returning a structured object instead of throwing exceptions for expected failures.</p><p>Instead of throwing exceptions, the method returns an object indicating whether it succeeded or failed and why.</p><h3 id="implementing-the-result-pattern">Implementing the Result Pattern</h3><p>To use the Result Pattern, we will create a simple application and then create the classes and methods. The complete source code with examples is available in this GitHub repository: <a target="_blank" href="https://github.com/zangassis/practicing-exception-handling">PracticingExceptionHandling source code</a>.</p><p>To create the base, you can use the command below in your terminal:</p><pre class=" language-bash"><code class="prism  language-bash">dotnet new web -o PracticingExceptionHandling
</code></pre><p>Open the application and create the following class within it:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">namespace</span> PracticingExceptionHandling<span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Result</span>
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">bool</span> IsSuccess <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span> Error <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token keyword">protected</span> <span class="token function">Result</span><span class="token punctuation">(</span><span class="token keyword">bool</span> isSuccess<span class="token punctuation">,</span> <span class="token keyword">string</span> error<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        IsSuccess <span class="token operator">=</span> isSuccess<span class="token punctuation">;</span>
        Error <span class="token operator">=</span> error<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> Result <span class="token function">Ok</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token keyword">new</span> <span class="token class-name">Result</span><span class="token punctuation">(</span><span class="token keyword">true</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">public</span> <span class="token keyword">static</span> Result <span class="token function">Fail</span><span class="token punctuation">(</span><span class="token keyword">string</span> error<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token keyword">new</span> <span class="token class-name">Result</span><span class="token punctuation">(</span><span class="token keyword">false</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span>T<span class="token operator">&gt;</span> <span class="token punctuation">:</span> Result
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> T Value <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token function">Result</span><span class="token punctuation">(</span>T <span class="token keyword">value</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">base</span><span class="token punctuation">(</span><span class="token keyword">true</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        Value <span class="token operator">=</span> <span class="token keyword">value</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token function">Result</span><span class="token punctuation">(</span><span class="token keyword">string</span> error<span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">base</span><span class="token punctuation">(</span><span class="token keyword">false</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> Result<span class="token operator">&lt;</span>T<span class="token operator">&gt;</span> <span class="token function">Ok</span><span class="token punctuation">(</span>T <span class="token keyword">value</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token keyword">new</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token keyword">value</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">new</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span>T<span class="token operator">&gt;</span> <span class="token function">Fail</span><span class="token punctuation">(</span><span class="token keyword">string</span> error<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token keyword">new</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Note that two <code>Result</code> classes are implemented, both aiming to explicitly represent the success or failure of an operation as well as the error details. The base class defines the common structure for any result. It has the <code>IsSuccess</code> property, which indicates whether the operation was successful, and the <code>Error</code> property, which contains the error message in case of failure.</p><p>The generic <code>Result&lt;T&gt;</code> class extends this idea to operations that return a value. When the operation is successful, in addition to <code>IsSuccess</code> being true, the result also carries a <code>Value</code> of type <code>T</code>. For this, there are two distinct private constructors: one for success, which receives the value, and another for failure, which receives only the error message. This avoids the creation of invalid states within the class itself.</p><p>The static methods <code>Ok</code> and <code>Fail</code> in the generic version follow the same pattern as the base class, but now allow data to be returned along with the result. This is useful in scenarios such as searches, validations or external integrations, where you want to return a value on success or a clear explanation on error, without throwing exceptions for expected situations.</p><p>An important point is that the consumer of the result must always check <code>IsSuccess</code> before accessing <code>Value</code>. This is a desirable behavior, as it forces the API user to explicitly handle failures, preventing silent errors or unexpected flows.</p><p>Now create a new class called <code>UserService</code> and add the following code to it:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">namespace</span> PracticingExceptionHandling<span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserService</span>
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> Result<span class="token operator">&lt;</span>User<span class="token operator">&gt;</span> <span class="token function">CreateUser</span><span class="token punctuation">(</span>User newUser<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>newUser<span class="token punctuation">.</span>Name<span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token keyword">return</span> Result<span class="token operator">&lt;</span>User<span class="token operator">&gt;</span><span class="token punctuation">.</span><span class="token function">Fail</span><span class="token punctuation">(</span><span class="token string">"Name is required"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">var</span> user <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">User</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            Id <span class="token operator">=</span> newUser<span class="token punctuation">.</span>Id<span class="token punctuation">,</span>
            Name <span class="token operator">=</span> newUser<span class="token punctuation">.</span>Name<span class="token punctuation">,</span>
            BankAccountNumber <span class="token operator">=</span> newUser<span class="token punctuation">.</span>BankAccountNumber<span class="token punctuation">,</span>
            Status <span class="token operator">=</span> <span class="token number">1</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> Result<span class="token operator">&lt;</span>User<span class="token operator">&gt;</span><span class="token punctuation">.</span><span class="token function">Ok</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Here we have the <code>CreateUser</code> method which validates whether the <code>Name</code> property is null or contains only spaces. If either of these conditions is true, the method immediately returns a failure result <code>Result&lt;User&gt;.Fail</code>, preventing the creation of an invalid user and explicitly stating the reason for the error.</p><p>If the validation passes, a new <code>User</code> object is instantiated with the data provided in the request, also applying a default value for <code>Status</code>. Finally, the method returns a success result <code>Result&lt;User&gt;.Ok</code>, encapsulating the created object.</p><p>The next step is to call the <code>CreateUser</code> method, so in the <code>Program</code> class, add the following endpoint:</p><pre class=" language-csharp"><code class="prism  language-csharp">app<span class="token punctuation">.</span><span class="token function">MapPost</span><span class="token punctuation">(</span><span class="token string">"/users/create"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>User newUser<span class="token punctuation">,</span> UserService userService<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span>
<span class="token punctuation">{</span>
    <span class="token keyword">var</span> result <span class="token operator">=</span> userService<span class="token punctuation">.</span><span class="token function">CreateUser</span><span class="token punctuation">(</span>newUser<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>result<span class="token punctuation">.</span>IsSuccess<span class="token punctuation">)</span>
        <span class="token keyword">return</span> Results<span class="token punctuation">.</span><span class="token function">BadRequest</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token punctuation">{</span> error <span class="token operator">=</span> result<span class="token punctuation">.</span>Error <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> Results<span class="token punctuation">.</span><span class="token function">Ok</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span>Value<span 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 this endpoint, we define a POST route <code>/users/create</code> that receives a User object and a <code>UserService</code> instance. Upon receiving the request, the endpoint calls the <code>CreateUser</code> method, which returns a <code>Result&lt;User&gt;</code>. This return encapsulates both success and potential failure.</p><p>Next, the endpoint checks the <code>IsSuccess</code> property. If the result indicates failure, it returns a <code>400 Bad Request</code>, including the error message (<code>result.Error</code>) in the response body, clearly explaining the reason for the rejection to the client. If the operation is successful, the endpoint returns a <code>200 OK</code> with the created object (<code>result.Value</code>).</p><p>In this way, we use the Result Pattern as a clear contract between the layers, which improves the readability and predictability of the API&rsquo;s behavior, reserving exceptions only for unpredictable scenarios.</p><h2 id="✨-expressive-exceptions">✨ Expressive Exceptions</h2><p>A common mistake when using exceptions is creating weak or generic exceptions. We&rsquo;ve already seen that exceptions should be reserved for unpredictable errors; in this case, when an error occurs, it&rsquo;s important to obtain as much information as possible about why that exception happened. Consider the example below:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Exception</span><span class="token punctuation">(</span><span class="token string">"User not found"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The problem here is that the system knows something went wrong but doesn&rsquo;t know exactly what went wrong (that is, the reason for the error).</p><p>To solve this, we can create a custom exception. Custom exceptions are classes that represent domain or application specific errors. Consider the following example:</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">UserNotFoundException</span> <span class="token punctuation">:</span> Exception
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token function">UserNotFoundException</span><span class="token punctuation">(</span><span class="token keyword">string</span> id<span class="token punctuation">)</span>
        <span class="token punctuation">:</span> <span class="token keyword">base</span><span class="token punctuation">(</span>$<span class="token string">"User with id {id} was not found"</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Now the error has an identity. It provides user details and makes it explicit that this is a domain exception and is important to the application, much more explicit than a generic exception.</p><p>Now see how it looks in the call:</p><p><strong>❌ Generic</strong></p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Exception</span><span class="token punctuation">(</span><span class="token string">"User not found"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p><strong>✅ Specific (Custom Exception)</strong></p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">UserNotFoundException</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>With custom exceptions, we obtain better tracking (logs), the possibility of specific handling and more expressive code.</p><h2 id="-creating-exceptions-with-helper-methods"> Creating Exceptions with Helper Methods</h2><p>When using custom exceptions, it&rsquo;s common to have duplicate exceptions, for example, when the same exception is thrown in multiple parts of the class. Note the example below:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token function">User</span><span class="token punctuation">(</span><span class="token keyword">string</span> name<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">InvalidUserException</span><span class="token punctuation">(</span><span class="token string">"Name cannot be empty"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    Name <span class="token operator">=</span> name<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">UpdateName</span><span class="token punctuation">(</span><span class="token keyword">string</span> name<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">InvalidUserException</span><span class="token punctuation">(</span><span class="token string">"Name cannot be empty"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    Name <span class="token operator">=</span> name<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>In both cases, the same exception is being thrown, using the same details. To reuse exceptions, we can create helper methods and even generic methods depending on the context in which they are used. In the case above, we can create a method that expects the name of a property and returns a custom exception and use it everywhere it is useful:</p><pre class=" language-csharp"><code class="prism  language-csharp">   <span class="token keyword">public</span> <span class="token function">User</span><span class="token punctuation">(</span><span class="token keyword">string</span> name<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token keyword">throw</span> <span class="token function">NewInvalidPropertyException</span><span class="token punctuation">(</span><span class="token string">"Name"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        Name <span class="token operator">=</span> name<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">UpdateName</span><span class="token punctuation">(</span><span class="token keyword">string</span> name<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token keyword">throw</span> <span class="token function">NewInvalidPropertyException</span><span class="token punctuation">(</span><span class="token string">"Name"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        Name <span class="token operator">=</span> name<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> InvalidUserException <span class="token function">NewInvalidPropertyException</span><span class="token punctuation">(</span><span class="token keyword">string</span> property<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">InvalidUserException</span><span class="token punctuation">(</span>$<span class="token string">"{property} cannot be empty"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
</code></pre><h2 id="-conclusion"> Conclusion</h2><p>Exceptions are an excellent feature of ASP.NET Core and are especially useful in unpredictable scenarios or as a last line of defense to prevent invalid states from progressing through the flow or persisting in the database. The problem arises when they are used to handle expected errors or in a generic way, without providing sufficient details.</p><p>In this post, we explore best practices in the use of exceptions and examine the Result Pattern as a more suitable alternative for predictable scenarios.</p><p>I hope this post helps you make better decisions when using exceptions, when to avoid them and how to apply them effectively in your applications.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Exploring the SLNX Solution File Format</h4></div><div class="col-8"><p class="u-fs16 u-mb0">If you&rsquo;ve worked with .NET for any length of time, you&rsquo;ve made peace with the .sln file. But as of .NET 10, we&rsquo;ve got .slnx. <a target="_blank" href="https://www.telerik.com/blogs/exploring-slnx-solution-file-format">Let&rsquo;s talk about what .slnx is</a>, why it exists, what it gets right and where you might get tripped up.</p></div></div></aside>]]></content>
  </entry>
</feed>
