<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Phinter Atieno</title>
    <description>The latest articles on Forem by Phinter Atieno (@phinteratienoo).</description>
    <link>https://forem.com/phinteratienoo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2291173%2F79685a51-bdb1-41c3-9b5f-75f3052285da.png</url>
      <title>Forem: Phinter Atieno</title>
      <link>https://forem.com/phinteratienoo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/phinteratienoo"/>
    <language>en</language>
    <item>
      <title>How to Stream Live Data into .NET MAUI DataGrid Using Firebase</title>
      <dc:creator>Phinter Atieno</dc:creator>
      <pubDate>Mon, 02 Mar 2026 05:42:36 +0000</pubDate>
      <link>https://forem.com/syncfusion/how-to-stream-live-data-into-net-maui-datagrid-using-firebase-1lg7</link>
      <guid>https://forem.com/syncfusion/how-to-stream-live-data-into-net-maui-datagrid-using-firebase-1lg7</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Use Firebase Realtime Database and .NET MAUI DataGrid to build live dashboards that auto‑refresh. Stream updates with Server-Sent Events (SSE), bind to an &lt;code&gt;ObservableCollection&lt;/code&gt;, and optionally poll for redundancy. Add templates, converters, and responsive styling for visuals, ideal for stock dashboards and trading-style UIs.&lt;/p&gt;

&lt;p&gt;Building real-time dashboards in .NET MAUI often comes with a key challenge: ensuring backend data changes instantly reflect in the UI. Static snapshots or delayed updates leave users with outdated views.&lt;/p&gt;

&lt;p&gt;In this guide, you’ll implement real-time updates in &lt;a href="https://www.syncfusion.com/maui-controls/maui-datagrid" rel="noopener noreferrer"&gt;Syncfusion&lt;sup&gt;®&lt;/sup&gt; .NET MAUI DataGrid&lt;/a&gt; by combining:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Firebase Realtime Database (RTDB)&lt;/strong&gt; for live data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firebase REST streaming (Server-Sent Events / SSE)&lt;/strong&gt; for near real-time change delivery.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ObservableCollection&lt;/code&gt; + &lt;code&gt;INotifyPropertyChanged&lt;/code&gt; so the Syncfusion .NET MAUI DataGrid refreshes automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Polling fallback&lt;/strong&gt; to recover if the stream drops.&lt;/li&gt;
&lt;li&gt;Optional styling via converters/templates (arrows, color coding, numeric formatting).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This pattern works well for dashboards and trading-style UIs across iOS, Android, Windows, and macOS (Mac Catalyst).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why choose the Syncfusion .NET MAUI DataGrid for live dashboards?
&lt;/h2&gt;

&lt;p&gt;When building real-time dashboards, the choice of grid control directly impacts performance, responsiveness, and user experience. Syncfusion .NET MAUI DataGrid stands out because it’s designed to handle continuous updates while keeping the UI smooth and professional. Its key advantages include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smooth, cell-level updates:&lt;/strong&gt; Responds instantly to &lt;code&gt;INotifyPropertyChanged&lt;/code&gt;, so cells refresh without re-rendering the entire grid.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich UX:&lt;/strong&gt; Sorting, selection, responsive columns, and templating let you build data-heavy UIs that still feel snappy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built for performance:&lt;/strong&gt; Virtualization and lightweight rendering keep scrolling fast even with frequent updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible styling:&lt;/strong&gt; Template columns, triggers, and styles let you emphasize what matters like rising prices, thresholds, or alerts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise-ready:&lt;/strong&gt; Backed by dedicated support, extensive documents, and production-grade reliability.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementing .NET MAUI DataGrid real-time updates (Firebase + SSE)
&lt;/h2&gt;

&lt;p&gt;Learn how to build a dynamic stock dashboard in .NET MAUI using Syncfusion DataGrid with live data updates, custom templates, and converters for a visually rich experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create and configure Firebase Realtime Database
&lt;/h3&gt;

&lt;p&gt;To enable real-time data updates, we need a data source that supports live synchronization. For this demo, we’ll use &lt;strong&gt;Firebase Realtime Database (RTDB)&lt;/strong&gt;, which provides continuous, instant updates across all connected devices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Firebase project
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;First, go to the &lt;a href="https://console.firebase.google.com/" rel="noopener noreferrer"&gt;Firebase console&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create a Project&lt;/strong&gt;, enter the project name, and click &lt;strong&gt;Continue&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;After the project is created, open the left navigation panel, expand &lt;strong&gt;Build&lt;/strong&gt;, and select &lt;strong&gt;Realtime Database&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In the Realtime Database section, click &lt;strong&gt;Create Database&lt;/strong&gt;, choose a database &lt;a href="https://firebase.google.com/docs/projects/locations" rel="noopener noreferrer"&gt;location&lt;/a&gt;, and set the initial security rules.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt; to configure the &lt;a href="https://firebase.google.com/docs/database/security" rel="noopener noreferrer"&gt;security rules&lt;/a&gt; for your database.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Start in test mode&lt;/strong&gt; and click &lt;strong&gt;Enable&lt;/strong&gt; at the bottom. Your database will now be created successfully.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Configure Database rules
&lt;/h3&gt;

&lt;p&gt;To manage access and security in your Firebase Realtime Database, you need to configure database rules.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Realtime Database&lt;/strong&gt; page in Firebase Console and click on the &lt;strong&gt;Rules&lt;/strong&gt; tab at the top.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;development&lt;/strong&gt;, you can allow read/write access without authentication and publish the rules.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;".read"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;".write"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;For &lt;strong&gt;production&lt;/strong&gt;, always apply stricter security by enabling Firebase Authentication to protect your data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get your Database URL&lt;/strong&gt;: Copy the RTDB URL from the Firebase console (e.g. &lt;code&gt;https://your-project-id-default-rtdb.firebaseio.com&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connects to Firebase&lt;/strong&gt;: Uses the project’s base URL to access the Firebase Realtime Database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loads initial Snapshot&lt;/strong&gt;: Fetches the latest stock data and updates headers and rows for the grid.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Starts background loops&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listens to real-time updates via Server-Sent Events (SSE) from Firebase.&lt;/li&gt;
&lt;li&gt;Periodically refreshes data every few seconds for redundancy.&lt;/li&gt;
&lt;li&gt;Randomly updates stock values locally to simulate live changes.&lt;/li&gt;
&lt;li&gt;Pushes simulated stock records to Firebase at a fixed interval.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Processes incoming data&lt;/strong&gt;: Converts JSON tokens into dynamic objects and updates the observable collections.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Notifies UI&lt;/strong&gt;: Updates headers and rows on the main thread, triggering the Syncfusion DataGrid to refresh automatically.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Add a Firebase streaming service (SSE)
&lt;/h3&gt;

&lt;p&gt;Firebase RTDB supports REST streaming using &lt;code&gt;text/event-stream&lt;/code&gt;. The service below opens a stream you can read continuously.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StocksService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;DbBase&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://your-project-id-default-rtdb.firebaseio.com"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;PathStocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/stocks.json"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;_authToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;HttpClient&lt;/span&gt; &lt;span class="n"&gt;_http&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Build Firebase URL with auth token&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;StocksUrl&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_authToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DbBase&lt;/span&gt;&lt;span class="p"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;PathStocks&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DbBase&lt;/span&gt;&lt;span class="p"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;PathStocks&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;?auth=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;_authToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Open SSE stream for real-time stock updates&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;TryOpenSseAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpRequestMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpMethod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StocksUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Accept"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"text/event-stream"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HttpCompletionOption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseHeadersRead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsSuccessStatusCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAsStreamAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Register the service
&lt;/h3&gt;

&lt;p&gt;This ensures a single instance of &lt;code&gt;StocksService&lt;/code&gt;streams data, and the &lt;code&gt;ViewModel&lt;/code&gt;updates data in real time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StocksService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Service for Firebase operations&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StockViewModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ViewModel for binding to UI&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; A singleton service prevents accidental multiple SSE connections and keeps resource usage predictable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Building the ViewModel for real-time updates
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;StockViewModel&lt;/code&gt; is responsible for managing the observable collections bound to the Syncfusion .NET MAUI DataGrid (headers and rows) to display live stock data. It acts as the bridge between the UI and the data source by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Connecting to &lt;code&gt;StocksService&lt;/code&gt;&lt;/strong&gt;: Handles Firebase operations such as retrieving and pushing data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loading snapshots&lt;/strong&gt;: Fetches the latest stock data and initializes the grid with headers and rows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Listening to Server‑Sent Events (SSE)&lt;/strong&gt;: Subscribes to Firebase’s real‑time stream to capture live updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Updating observable collections&lt;/strong&gt;: Ensures that changes in stock data automatically refresh the DataGrid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This &lt;code&gt;ViewModel&lt;/code&gt; pattern keeps the UI responsive and ensures that stock dashboards reflect the latest data without manual refreshes.&lt;/p&gt;

&lt;p&gt;Code snippet to achieve this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StockViewModel&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;InitializeAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Fetch and load the latest data from the database&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;LoadSnapshotAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Start real-time data streaming from Firebase using SSE&lt;/span&gt;
        &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;StreamLoopAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_streamCts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="c1"&gt;// Start periodic polling as a fallback to ensure data consistency&lt;/span&gt;
        &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;PollLoopAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;_pollCts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="c1"&gt;// Apply local demo changes to simulate live updates&lt;/span&gt;
        &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;DemoChangeLoopAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;_demoCts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="c1"&gt;// Push records to Firebase&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EnableRemoteSimulation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;RemoteSimLoopAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RemoteSimulationPeriod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_remoteSimCts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Check the &lt;code&gt;StockViewModel&lt;/code&gt; class on &lt;a href="https://github.com/SyncfusionExamples/How-to-showcase-live-data-updates-in-the-.NET-MAUI-DataGrid/blob/LiveUpdates/LiveUpdates_DataBase/LiveUpdates_DataBase/ViewModels/StockViewModel.cs" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; for more details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Designing the XAML layout for real-time updates
&lt;/h3&gt;

&lt;p&gt;In this step, you need to bind the DataGrid to the Stocks collection in the &lt;code&gt;ViewModel&lt;/code&gt;, ensuring that any changes in the data source are instantly reflected in the UI. We also integrate  &lt;code&gt;TextForegroundConverter&lt;/code&gt;to apply conditional formatting for stock changes.&lt;/p&gt;

&lt;p&gt;Here’s how you can do it in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ContentPage.Resources&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;local:SignToColorConverter&lt;/span&gt; &lt;span class="na"&gt;x:Key=&lt;/span&gt;&lt;span class="s"&gt;"SignToColor"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;local:SignToArrowConverter&lt;/span&gt; &lt;span class="na"&gt;x:Key=&lt;/span&gt;&lt;span class="s"&gt;"SignToArrow"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Style&lt;/span&gt; &lt;span class="na"&gt;TargetType=&lt;/span&gt;&lt;span class="s"&gt;"syncfusion:DataGridHeaderCell"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"TextColor"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Black"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontAttributes"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Bold"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ContentPage.Resources&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;Grid&lt;/span&gt; &lt;span class="na"&gt;RowDefinitions=&lt;/span&gt;&lt;span class="s"&gt;"*"&lt;/span&gt; &lt;span class="na"&gt;Padding=&lt;/span&gt;&lt;span class="s"&gt;"12"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;syncfusion:SfDataGrid&lt;/span&gt; &lt;span class="na"&gt;x:Name=&lt;/span&gt;&lt;span class="s"&gt;"grid"&lt;/span&gt;
                           &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Rows}"&lt;/span&gt;                
                           &lt;span class="na"&gt;ColumnWidthMode=&lt;/span&gt;&lt;span class="s"&gt;"Auto"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Grid&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By following these steps, you’ve built a responsive, real-time stock data grid in .NET MAUI using the Syncfusion DataGrid. It streams live updates, applies dynamic styling instantly, and runs smoothly on iOS, Android, macOS, and Windows, perfect for stock dashboards, trading apps, or any scenario that needs up-to-the-second data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FLive-Stock-Data-Update-in-.NET-MAUI-Syncfusion-DataGrid.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FLive-Stock-Data-Update-in-.NET-MAUI-Syncfusion-DataGrid.gif" alt="Live stock data update in .NET MAUI Syncfusion DataGrid" width="750" height="583"&gt;&lt;/a&gt;&lt;br&gt;Live stock data update in .NET MAUI Syncfusion DataGrid
  &lt;/p&gt;

&lt;h2&gt;
  
  
  Enterprise considerations for long-running live dashboards
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resilience&lt;/strong&gt;: Add reconnect logic for SSE drops and keep polling as a controlled fallback (with backoff).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI thread safety&lt;/strong&gt;: Always update collections on the main thread (Dispatcher / MainThread).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance at scale:&lt;/strong&gt; Prefer updating properties on existing rows over rebuilding the entire &lt;strong&gt;&lt;code&gt;ItemsSource&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory safety:&lt;/strong&gt; Dispose streams, cancel tokens, and unsubscribe handlers when pages close.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security:&lt;/strong&gt; Never ship “test mode” rules; use &lt;code&gt;Auth + strict RTDB&lt;/code&gt; rules and avoid embedding long-lived secrets in mobile apps.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Build vs buy (practical take)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Build your own grid&lt;/strong&gt; only if you need a very narrow UI with minimal features and can accept long-term maintenance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a mature DataGrid&lt;/strong&gt; when you need virtualization, templating, sorting/selection, and reliable UI performance under frequent updates, especially for enterprise dashboards.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is Firebase “test mode” safe to use in production?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Test mode allows open read/write access. For production, enable Firebase authentication and enforce strict, least-privilege realtime Database security rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does the DataGrid handle frequent updates at scale?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Syncfusion DataGrid supports virtualization and cell-level refresh. If your row models implement &lt;code&gt;INotifyPropertyChanged&lt;/code&gt; and you update properties (instead of replacing the whole item/&lt;code&gt;ItemsSource&lt;/code&gt;), the grid can refresh changed cells with minimal redraw.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I ensure UI thread safety when updating collections?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Always marshal collection and bound-property updates to the UI thread (for example via &lt;code&gt;MainThread.BeginInvokeOnMainThread / Dispatcher&lt;/code&gt;). Updating &lt;code&gt;ObservableCollection&lt;/code&gt; from background tasks can cause exceptions or inconsistent rendering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What should I do if the data stream drops?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add reconnection logic (with backoff) and keep periodic polling/state rehydration as a fallback. This restores local correctness if SSE disconnects or misses events.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub reference
&lt;/h2&gt;

&lt;p&gt;For more details, refer to the complete real-time data update project for .NET MAUI DataGrid in the &lt;a href="https://github.com/SyncfusionExamples/How-to-showcase-live-data-updates-in-the-.NET-MAUI-DataGrid/tree/master" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thanks for reading! In this blog, we explored how to implement live data updates in &lt;a href="https://www.syncfusion.com/maui-controls/maui-datagrid" rel="noopener noreferrer"&gt;.NET MAUI DataGrid&lt;/a&gt;. With real‑time synchronization powered by Firebase, your dashboards stay accurate and responsive. The Syncfusion DataGrid enhances this further with dynamic styling, adaptive layouts, and seamless cross‑platform support. Using these techniques, you can build stock dashboards, trading platforms, or any app that requires instant and reliable data updates, making your applications more professional, engaging, and efficient.&lt;/p&gt;

&lt;p&gt;If you’re a Syncfusion user, you can download the setup from the &lt;a href="https://www.syncfusion.com/sales/pricing" rel="noopener noreferrer"&gt;license and downloads&lt;/a&gt; page. Otherwise, you can download a free &lt;a href="https://www.syncfusion.com/downloads/" rel="noopener noreferrer"&gt;30-day trial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also contact us through our &lt;a href="https://www.syncfusion.com/forums" rel="noopener noreferrer"&gt;support forum&lt;/a&gt;, &lt;a href="https://support.syncfusion.com/" rel="noopener noreferrer"&gt;support portal&lt;/a&gt;, or &lt;a href="https://www.syncfusion.com/feedback" rel="noopener noreferrer"&gt;feedback portal&lt;/a&gt; for queries. We are always happy to assist you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Blogs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/support-ticket-dashboard-in-maui-grid" rel="noopener noreferrer"&gt;Building a Support Ticket Dashboard with .NET MAUI DataGrid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/net-maui-datagrid-styling" rel="noopener noreferrer"&gt;Styling Made Easy in .NET MAUI DataGrid: A Simplified Customization Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/save-chat-to-firebase-database-maui" rel="noopener noreferrer"&gt;Save Chat History to Firebase Realtime Database using the .NET MAUI Chat Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/load-firebase-cloud-pdfs-in-maui" rel="noopener noreferrer"&gt;Load PDFs from Firebase Cloud Storage Using .NET MAUI PDF Viewer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally published at &lt;a href="https://www.syncfusion.com/blogs/post/stream-live-data-maui-datagrid-firebase" rel="noopener noreferrer"&gt;Syncfusion.com.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>netmaui</category>
      <category>datagrid</category>
      <category>firebaseintegration</category>
      <category>realtimedashboards</category>
    </item>
    <item>
      <title>React 19 Suspense for Data Fetching: A New Model for Async UI</title>
      <dc:creator>Phinter Atieno</dc:creator>
      <pubDate>Thu, 26 Feb 2026 14:30:17 +0000</pubDate>
      <link>https://forem.com/syncfusion/react-19-suspense-for-data-fetching-a-new-model-for-async-ui-23db</link>
      <guid>https://forem.com/syncfusion/react-19-suspense-for-data-fetching-a-new-model-for-async-ui-23db</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; React Suspense for data fetching allows components to render automatically as soon as their data is ready without manually wiring &lt;code&gt;useEffect()&lt;/code&gt;, &lt;code&gt;useState()&lt;/code&gt;, loading states, or re‑render logic. With React 19’s new &lt;code&gt;use()&lt;/code&gt; API and Suspense boundaries, you can run nested or parallel data loading, handle failures with error boundaries, keep interactions responsive using &lt;code&gt;useTransition()&lt;/code&gt;, and even stream server-rendered content progressively.&lt;/p&gt;

&lt;p&gt;Users don’t care how your app fetches data; they care that the UI feels fast and stable. React 18 took the first step toward this with Suspense and lazy loading, allowing React apps to defer non‑critical code and avoid blocking the main UI thread.&lt;/p&gt;

&lt;p&gt;React 19 builds on that foundation by turning Suspense into a more capable async rendering system. With the new &lt;code&gt;use()&lt;/code&gt; API and transitions, React can coordinate loading, fallbacks, and server‑streamed content in a much more predictable way.&lt;/p&gt;

&lt;p&gt;This guide explores what’s new in React 19 Suspense, where it fits in modern rendering, and how it changes traditional data‑fetching patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Suspense exists (and where it fits in rendering)
&lt;/h2&gt;

&lt;p&gt;React’s push toward better performance started with a simple idea used heavily at Meta: load as little as possible, as early as possible. To give users a fast UI, we want small bundles that render quickly, but we also want data and code available the moment the user needs them.&lt;/p&gt;

&lt;p&gt;Techniques like tree‑shaking, code‑splitting, preloading, and predictive loading helped reduce bundle size and load assets earlier, but something was still missing. React needed a way to coordinate what’s being fetched and what’s being rendered.&lt;/p&gt;

&lt;p&gt;That gap is exactly where Suspense fits. It sits between your loading code and your UI, deciding what to show while data, components, or scripts are still on the way. Modern apps often struggle to render quickly because of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slow server responses.&lt;/li&gt;
&lt;li&gt;Data dependencies (one request needs another).&lt;/li&gt;
&lt;li&gt;Third-party scripts blocking rendering.&lt;/li&gt;
&lt;li&gt;Components that can’t render until data exists.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Suspense provides a structured way to handle all of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If something is still loading, React can show a fallback.&lt;/li&gt;
&lt;li&gt;When it’s ready, React renders the UI.&lt;/li&gt;
&lt;li&gt;If it fails, React throws the error (you handle it with an error boundary).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes Suspense a core part of the “load early, render progressively” approach. With React 19’s new &lt;code&gt;use()&lt;/code&gt; and &lt;code&gt;useTransition()&lt;/code&gt; hooks, Suspense evolves from a simple fallback mechanism into a full async rendering tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  React 18 recap: Suspense for code-splitting
&lt;/h2&gt;

&lt;p&gt;Route‑level lazy loading is one of the simplest and most effective uses of Suspense. It splits your bundle and shows a fallback while the route chunk loads, no manual loading state needed.&lt;/p&gt;

&lt;p&gt;Implementation example:&lt;/p&gt;

&lt;p&gt;jsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lazy&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BrowserRouter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Lazy load different pages&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/Home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Dashboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/Dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/Settings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Custom loading component&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LoadingSpinner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;textAlign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;50px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BrowserRouter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoadingSpinner&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Routes&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Home&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Dashboard&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/settings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Settings&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Routes&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/BrowserRouter&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before diving into how Suspense speeds up loading, let’s revisit how React traditionally fetched and rendered data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Traditional data-fetching and why it feels clunky
&lt;/h2&gt;

&lt;p&gt;Most React apps use one of two familiar patterns for fetching and rendering data. They work, but both require extra state management and force React to render the UI more than once.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fetch on render
&lt;/h3&gt;

&lt;p&gt;In this approach, the component mounts first. Only after the initial render does it start fetching data. While the request is in progress, you show a loading state; once the data arrives, the component renders again with real content.&lt;/p&gt;

&lt;p&gt;Here’s how you can do it in code:&lt;/p&gt;

&lt;p&gt;jsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PostDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;postDetails&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPostDetails&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://jsonplaceholder.typicode.com/posts/1/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setPostDetails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;postDetails&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;postDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;postDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fetch then render
&lt;/h3&gt;

&lt;p&gt;Here, data is requested immediately, but the component still can’t render meaningful UI until the fetch completes. You still end up managing loading states and triggering a second render when the data arrives.&lt;/p&gt;

&lt;p&gt;Try this in your code:&lt;/p&gt;

&lt;p&gt;jsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchPostDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://jsonplaceholder.typicode.com/posts/1/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;postDetails&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPostDetails&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fetchPostDetails&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setPostDetails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;postDetails&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PostDetails&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;postDetails&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PostDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both approaches rely on two different hooks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;useEffect()&lt;/code&gt; to trigger the fetch.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;useState()&lt;/code&gt; to store the result, plus loading and error states.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because the component must render first and then fetch, React ends up rendering twice, once for the placeholder UI, then again for the real content. As your app grows, managing these states across multiple components becomes repetitive and error‑prone.&lt;/p&gt;

&lt;p&gt;What if we can streamline everything, removing the need for the &lt;code&gt;useEffect()&lt;/code&gt; and &lt;code&gt;useState()&lt;/code&gt; hooks altogether, while still being able to efficiently handle the loading and error state?&lt;/p&gt;

&lt;p&gt;That is what &lt;strong&gt;Suspense&lt;/strong&gt; is here for.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Suspense for data fetching
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How does Suspense work?
&lt;/h3&gt;

&lt;p&gt;When React is rendering the component, and it discovers the Suspense in its DOM tree, it checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If any child of Suspense is waiting for asynchronous operations like promises, to complete.&lt;/li&gt;
&lt;li&gt;React suspends the rendering of the children and shows the fallback UI.&lt;/li&gt;
&lt;li&gt;When the async work completes, then React renders the UI.&lt;/li&gt;
&lt;li&gt;If the async work fails, then Suspense will throw errors, and it has to be handled through an error boundary or explicitly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives the user the most optimal experience, and you can separate or club different components in their own Suspense as you wish.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FFallback-UI-shown-while-child-components-await-async-operations.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FFallback-UI-shown-while-child-components-await-async-operations.png" alt="Fallback UI shown while child components await async operations" width="800" height="206"&gt;&lt;/a&gt;&lt;br&gt;Fallback UI shown while child components await async operations
  &lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Suspense with data fetching
&lt;/h3&gt;

&lt;p&gt;You can pass a promise (async task) directly to the &lt;code&gt;use()&lt;/code&gt; hook within a component and wrap the component inside the Suspense with a fallback UI.&lt;/p&gt;

&lt;p&gt;The component renders only after the promise inside the &lt;code&gt;use()&lt;/code&gt; hook has resolved. Below is the code you need:&lt;/p&gt;

&lt;p&gt;jsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Simulated API calls that return promises&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`user&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;@example.com`&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchPosts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;First Post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Second Post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content 2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Component using React 19's `use` hook&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fetchUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserPosts&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fetchPosts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h4&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h4&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;))}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React 19 treats the &lt;strong&gt;&lt;code&gt;use()&lt;/code&gt;&lt;/strong&gt; hook as a first‑class, framework‑agnostic primitive for reading asynchronous values. You can pass a plain promise directly to &lt;code&gt;use()&lt;/code&gt;, and React will automatically suspend the component until that promise resolves. Suspense handles the waiting logic, so you don’t need effects, state variables, or manual loading flags.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;use()&lt;/code&gt; hook works in both client and server components, but server components should prefer async/await instead of &lt;code&gt;use()&lt;/code&gt; for two reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Async by default:&lt;/strong&gt; React 19 supports fully asynchronous server components. Because the server waits for the data before sending HTML to the client, there’s no need for a Suspense fallback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No boundary required:&lt;/strong&gt; Passing a promise to &lt;code&gt;use()&lt;/code&gt; triggers Suspense and requires a boundary in the component tree. With async/await on the server, you can wait for the data directly without introducing a Suspense wrapper.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since &lt;code&gt;use()&lt;/code&gt; always activates a Suspense boundary, it must only be called within a Suspense‑wrapped subtree. Calling &lt;code&gt;use()&lt;/code&gt; outside a boundary causes React to throw because there’s nowhere to display the fallback.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nested Suspense
&lt;/h3&gt;

&lt;p&gt;You can nest Suspense boundaries when different parts of the UI depend on separate asynchronous operations. In a nested setup, the parent component must finish rendering before the child begins its own data‑fetching logic. Each boundary controls its own loading state and resolves independently.&lt;/p&gt;

&lt;p&gt;Implementation example:&lt;/p&gt;

&lt;p&gt;jsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;NestedSuspenseExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Nested&lt;/span&gt; &lt;span class="nx"&gt;Suspense&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Outer Suspense for user profile */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoadingSkeleton&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading profile...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserProfile&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Inner Suspense for posts - loads independently */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoadingSkeleton&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading posts...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserPosts&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nested boundaries are useful when parts of the UI depend on each other, but you still want the child sections to load independently once the parent has completed its async work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parallel data-fetching in Suspense
&lt;/h3&gt;

&lt;p&gt;If the UI sections do not depend on each other, you can place separate Suspense boundaries side by side. Each boundary begins loading as soon as its component renders, allowing React to fetch multiple async resources in parallel.&lt;/p&gt;

&lt;p&gt;Here’s how you can do it in code:&lt;/p&gt;

&lt;p&gt;jsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ParallelSuspenseExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Parallel&lt;/span&gt; &lt;span class="nx"&gt;Suspense&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* First Suspense for user profile */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoadingSkeleton&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading profile...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserProfile&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Second Suspense for posts - loads independently */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoadingSkeleton&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading posts...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserPosts&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Multiple parallel async calls inside a single boundary
&lt;/h3&gt;

&lt;p&gt;Sometimes you need multiple async operations, such as fetching both a user and their posts, to run at the same time. With the &lt;code&gt;use()&lt;/code&gt; hook, you can initiate them together inside one component, and Suspense will wait until all async work has completed before rendering the UI.&lt;/p&gt;

&lt;p&gt;Implementation example:&lt;/p&gt;

&lt;p&gt;jsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MultipleAsyncCallsExample&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fetchUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fetchPosts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserPosts&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserProfile&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Multiple&lt;/span&gt; &lt;span class="nx"&gt;parallel&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;calls&lt;/span&gt; &lt;span class="nx"&gt;within&lt;/span&gt; &lt;span class="nx"&gt;suspense&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Outer Suspense for user profile */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoadingSkeleton&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading data...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MultipleAsyncCallsExample&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both requests run in parallel, and the fallback remains visible until every async task resolves. This eliminates the boilerplate &lt;code&gt;useEffect()&lt;/code&gt; and &lt;code&gt;useState()&lt;/code&gt; patterns and lets React handle async coordination automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Coordinated reveal with SuspenseList (experimental)
&lt;/h3&gt;

&lt;p&gt;For more control over how multiple Suspense boundaries appear on the screen, React provides &lt;code&gt;SuspenseList&lt;/code&gt;. It lets you specify reveal order, useful when rendering long lists or progressively loaded sections that should appear top‑to‑bottom.&lt;/p&gt;

&lt;p&gt;Here’s how you can do it in code:&lt;/p&gt;

&lt;p&gt;jsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SuspenseListExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SuspenseList&lt;/span&gt; &lt;span class="nx"&gt;revealOrder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;forwards&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* First Suspense for user profile */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoadingSkeleton&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading profile...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserProfile&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Second Suspense for posts - loads independently */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoadingSkeleton&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading posts...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserPosts&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/SuspenseList&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach works well when you have a large list, and you want to do the step-by-step reveal with the reading flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;SuspenseList&lt;/code&gt; is still experimental; avoid using it in production or use it with care until stabilized.&lt;/p&gt;

&lt;h3&gt;
  
  
  State refreshing
&lt;/h3&gt;

&lt;p&gt;React’s &lt;code&gt;useTransition()&lt;/code&gt; hook lets you mark certain state updates as non‑urgent, keeping the UI responsive while new data loads. When you wrap an update with &lt;code&gt;startTransition()&lt;/code&gt;, React delays the visual update, triggers the async work, and Suspense handles the loading fallback, all without blocking the current UI.&lt;/p&gt;

&lt;p&gt;Below is the code you need:&lt;/p&gt;

&lt;p&gt;jsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;TransitionExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUserId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isPending&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;startTransition&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTransition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;switchUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;startTransition&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setUserId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;Transitions&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
            &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;switchUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
            &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isPending&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;
              &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;
                &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-blue-600 text-white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-gray-200 text-gray-700 hover:bg-gray-300&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;isPending&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;opacity-50 cursor-not-allowed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isPending&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Transitioning&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoadingSkeleton&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading user...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserProfile&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Transitions ensure the UI stays interactive. The current screen remains visible while React fetches the next user, and Suspense swaps in the fallback only for the sections that need new data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling error
&lt;/h3&gt;

&lt;p&gt;Suspense manages loading, but it doesn’t catch async errors. For that, React relies on Error Boundaries. By wrapping Suspense inside an error boundary, you can show a clear error message and provide a retry mechanism when async work fails.&lt;/p&gt;

&lt;p&gt;Here’s how you can do it in code:&lt;/p&gt;

&lt;p&gt;jsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ErrorBoundary&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hasError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;getDerivedStateFromError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hasError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;componentDidCatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errorInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error caught:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errorInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-red-50 border border-red-200 rounded-lg p-4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-red-800 font-semibold mb-2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="nx"&gt;Occurred&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-red-600 text-sm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
            &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;hasError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;})}&lt;/span&gt;
            &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mt-3 px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nx"&gt;Retry&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchWithError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shouldFail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shouldFail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to fetch data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Success!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;DataWithError&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;shouldFail&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fetchWithError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shouldFail&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-green-600 font-medium&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ErrorBoundaryExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;shouldFail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setShouldFail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setKey&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;space-y-4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-2xl font-bold text-gray-800&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="nx"&gt;Boundaries&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex gap-2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
          &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setShouldFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nf"&gt;setKey&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}}&lt;/span&gt;
          &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Fetch&lt;/span&gt; &lt;span class="nx"&gt;Success&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
          &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setShouldFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nf"&gt;setKey&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}}&lt;/span&gt;
          &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Fetch&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ErrorBoundary&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoadingSkeleton&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fetching data...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DataWithError&lt;/span&gt; &lt;span class="nx"&gt;shouldFail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;shouldFail&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ErrorBoundary&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The retry simply forces a re-render, re‑executing the async work inside Suspense.&lt;/p&gt;

&lt;p&gt;You can wrap individual Suspense boundaries, nested boundaries, or entire &lt;code&gt;SuspenseLists&lt;/code&gt; inside an error boundary, React handles each boundary independently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Streaming server-side rendered content
&lt;/h3&gt;

&lt;p&gt;With Suspense, we can highly optimize the rendering of the server-side content. The server can stream the partial content, and the browser will render it in parts.&lt;/p&gt;

&lt;p&gt;This is how it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React starts constructing the content on the server.&lt;/li&gt;
&lt;li&gt;Once it encounters the Suspense, it streams the constructed content to the browser.&lt;/li&gt;
&lt;li&gt;The browser starts rendering the received content.&lt;/li&gt;
&lt;li&gt;Once the async operation is completed, React sends the remaining content.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This works properly because the fallback UI is added to the main bundle, which helps React to render it on the browser while waiting for the server to stream the remaining content.&lt;/p&gt;

&lt;p&gt;Implementation example:&lt;/p&gt;

&lt;p&gt;jsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;renderToPipeableStream&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom/server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;}&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MainComponent&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Server-side rendering logic&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pipe&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;renderToPipeableStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is really helpful as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server starts streaming partial content, and browsers start rendering it, resulting in faster first paint.&lt;/li&gt;
&lt;li&gt;User sees progressive rendering over a blank screen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To make the most out of Suspense, rather than using traditional loading, you can use skeleton loading to minimize the layout shifting.&lt;/p&gt;

&lt;p&gt;jsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoadingSkeleton&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading posts...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserPosts&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thank you for reading! Suspense is a great addition in React 19 that really solves some of the core rendering problems on the browser, providing the best optimal experience. But make sure you are not overdoing it by wrapping the components that do not require fallbacks.&lt;/p&gt;

&lt;p&gt;Having an audit check could be helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI fallbacks should match the layout of the component to minimize layout jumps.&lt;/li&gt;
&lt;li&gt;Only necessary components should be isolated with their suspense boundary.&lt;/li&gt;
&lt;li&gt;Are the crucial components of error handled properly?&lt;/li&gt;
&lt;li&gt;Test everything on a throttled, slower network before shipping.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your perspective can help others, leave a comment with what worked or what you’re still exploring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Blogs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/build-query-builder-in-react-19" rel="noopener noreferrer"&gt;Building a Modern Query Builder with React 19 Server Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/task-management-app-react19-nextjs" rel="noopener noreferrer"&gt;Building an Optimistic UI Task Management App with React 19 and Next.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/implement-jwt-authentication-in-react" rel="noopener noreferrer"&gt;JWT Authentication in React: Secure Routes, Context, and Token Handling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/react-animation-libraries-comparison" rel="noopener noreferrer"&gt;Choosing a React Animation Library: Performance Trade-Offs in Real Apps&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally published at &lt;a href="https://www.syncfusion.com/blogs/post/react-19-suspense-for-data-fetching" rel="noopener noreferrer"&gt;Syncfusion.com.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>frontend</category>
      <category>javascript</category>
      <category>react19</category>
    </item>
    <item>
      <title>How to Add Email and Toast Reminders to a .NET MAUI Scheduler</title>
      <dc:creator>Phinter Atieno</dc:creator>
      <pubDate>Thu, 26 Feb 2026 12:31:44 +0000</pubDate>
      <link>https://forem.com/syncfusion/how-to-add-email-and-toast-reminders-to-a-net-maui-scheduler-57hh</link>
      <guid>https://forem.com/syncfusion/how-to-add-email-and-toast-reminders-to-a-net-maui-scheduler-57hh</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Learn how to implement reliable event reminders in a .NET MAUI Scheduler using SMTP-based email notifications and cross-platform toast alerts. This guide shows how to design reminder workflows that improve user experience, ensure timely notifications, and work consistently across devices, ideal for calendar, booking, and productivity apps.&lt;/p&gt;

&lt;p&gt;Ever missed a critical meeting because your calendar didn’t remind you? It happens to all of us, especially when we’re juggling multiple tasks in a packed schedule. Adding an appointment is simple, but remembering at the right time is the real challenge.&lt;/p&gt;

&lt;p&gt;That’s where event reminders and email notifications make all the difference. They deliver timely alerts and follow-ups, helping you stay organized, productive, and stress-free.&lt;/p&gt;

&lt;p&gt;In this blog, we’ll walk through the essential steps to integrate appointment scheduling with system notifications and email reminders using the &lt;a href="https://www.syncfusion.com/maui-controls/maui-scheduler" rel="noopener noreferrer"&gt;Syncfusion&lt;sup&gt;®&lt;/sup&gt; .NET MAUI Scheduler&lt;/a&gt;. This approach ensures your users stay informed, organized, and never miss an important event.&lt;/p&gt;

&lt;p&gt;Now that we understand the value of reminders, let’s initialize the Scheduler and start adding reminders.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Initializing Syncfusion .NET MAUI Scheduler
&lt;/h2&gt;

&lt;p&gt;To begin, add the Scheduler control to your XAML page and bind its &lt;a href="https://help.syncfusion.com/cr/maui/Syncfusion.Maui.Scheduler.SfScheduler.html#Syncfusion_Maui_Scheduler_SfScheduler_AppointmentsSource" rel="noopener noreferrer"&gt;AppointmentsSource&lt;/a&gt; property to an &lt;code&gt;ObservableCollection&amp;lt;SchedulerAppointment&amp;gt;&lt;/code&gt; in your &lt;a href="https://help.syncfusion.com/maui/scheduler/getting-started?cs-save-lang=1&amp;amp;cs-lang=csharp#create-view-model" rel="noopener noreferrer"&gt;ViewModel&lt;/a&gt;. This collection stores all your events and keeps the UI in sync with your data.&lt;/p&gt;

&lt;p&gt;Here’s how you can do it in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8" ?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ContentPage&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.microsoft.com/dotnet/2021/maui"&lt;/span&gt;
             &lt;span class="na"&gt;xmlns:x=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.microsoft.com/winfx/2009/xaml"&lt;/span&gt;
             &lt;span class="na"&gt;xmlns:scheduler=&lt;/span&gt;&lt;span class="s"&gt;"clr-namespace:Syncfusion.Maui.Scheduler;assembly=Syncfusion.Maui.Scheduler"&lt;/span&gt;
             &lt;span class="na"&gt;x:Class=&lt;/span&gt;&lt;span class="s"&gt;"Event_Reminder.MainPage"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;scheduler:SfScheduler&lt;/span&gt; &lt;span class="na"&gt;x:Name=&lt;/span&gt;&lt;span class="s"&gt;"Scheduler"&lt;/span&gt;
                       &lt;span class="na"&gt;View=&lt;/span&gt;&lt;span class="s"&gt;"Week"&lt;/span&gt;
                       &lt;span class="na"&gt;AllowedViews=&lt;/span&gt;&lt;span class="s"&gt;"Day, Week, WorkWeek, Month"&lt;/span&gt;
                       &lt;span class="na"&gt;EnableReminder=&lt;/span&gt;&lt;span class="s"&gt;"True"&lt;/span&gt;
                       &lt;span class="na"&gt;AppointmentsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Appointments}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/scheduler:SfScheduler&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ContentPage&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For more details, check out the Getting Started with the .NET MAUI Scheduler &lt;a href="https://help.syncfusion.com/maui/scheduler/getting-started" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Adding appointments to the Scheduler via popup
&lt;/h2&gt;

&lt;p&gt;You can collect event details through a popup that includes fields for Subject, Start Time, End Time, Recurrence Rule, and Save/Cancel buttons. When a user taps a Scheduler cell, the popup opens, allowing them to enter event information.&lt;/p&gt;

&lt;p&gt;When the &lt;strong&gt;Save&lt;/strong&gt; button is clicked, the appointment details are collected and added to the appointment list in the .NET MAUI Scheduler.&lt;/p&gt;

&lt;p&gt;Here’s the XAML code example for the appointment popup UI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ContentView&lt;/span&gt; &lt;span class="na"&gt;x:Name=&lt;/span&gt;&lt;span class="s"&gt;"AddPopup"&lt;/span&gt;
             &lt;span class="na"&gt;IsVisible=&lt;/span&gt;&lt;span class="s"&gt;"{Binding IsAddPopupVisible}"&lt;/span&gt;
             &lt;span class="na"&gt;BackgroundColor=&lt;/span&gt;&lt;span class="s"&gt;"#80000000"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Grid&lt;/span&gt; &lt;span class="na"&gt;VerticalOptions=&lt;/span&gt;&lt;span class="s"&gt;"Center"&lt;/span&gt; &lt;span class="na"&gt;HorizontalOptions=&lt;/span&gt;&lt;span class="s"&gt;"Center"&lt;/span&gt; &lt;span class="na"&gt;Padding=&lt;/span&gt;&lt;span class="s"&gt;"16"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Border&lt;/span&gt; &lt;span class="na"&gt;BackgroundColor=&lt;/span&gt;&lt;span class="s"&gt;"White"&lt;/span&gt; &lt;span class="na"&gt;Stroke=&lt;/span&gt;&lt;span class="s"&gt;"LightGray"&lt;/span&gt; &lt;span class="na"&gt;StrokeThickness=&lt;/span&gt;&lt;span class="s"&gt;"1.5"&lt;/span&gt;
            &lt;span class="na"&gt;StrokeShape=&lt;/span&gt;&lt;span class="s"&gt;"RoundRectangle 12"&lt;/span&gt; &lt;span class="na"&gt;Padding=&lt;/span&gt;&lt;span class="s"&gt;"16"&lt;/span&gt; &lt;span class="na"&gt;WidthRequest=&lt;/span&gt;&lt;span class="s"&gt;"300"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Grid&lt;/span&gt; &lt;span class="na"&gt;RowDefinitions=&lt;/span&gt;&lt;span class="s"&gt;"Auto,Auto,Auto,Auto"&lt;/span&gt; &lt;span class="na"&gt;ColumnDefinitions=&lt;/span&gt;&lt;span class="s"&gt;"Auto,*"&lt;/span&gt; &lt;span class="na"&gt;RowSpacing=&lt;/span&gt;&lt;span class="s"&gt;"8"&lt;/span&gt; &lt;span class="na"&gt;ColumnSpacing=&lt;/span&gt;&lt;span class="s"&gt;"12"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- Title --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Add Event"&lt;/span&gt; &lt;span class="na"&gt;Grid.ColumnSpan=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt; &lt;span class="na"&gt;FontAttributes=&lt;/span&gt;&lt;span class="s"&gt;"Bold"&lt;/span&gt; &lt;span class="na"&gt;FontSize=&lt;/span&gt;&lt;span class="s"&gt;"18"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- Subject --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Subject"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Entry&lt;/span&gt; &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;Grid.Column=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"{Binding NewSubject}"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- Start Date &amp;amp; Time --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Start"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Grid&lt;/span&gt; &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt; &lt;span class="na"&gt;Grid.Column=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;ColumnDefinitions=&lt;/span&gt;&lt;span class="s"&gt;"*,Auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;DatePicker&lt;/span&gt; &lt;span class="na"&gt;Date=&lt;/span&gt;&lt;span class="s"&gt;"{Binding NewStartDate}"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;TimePicker&lt;/span&gt; &lt;span class="na"&gt;Grid.Column=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;Time=&lt;/span&gt;&lt;span class="s"&gt;"{Binding NewStartTime}"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Grid&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- End Date &amp;amp; Time --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"End"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Grid&lt;/span&gt; &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt; &lt;span class="na"&gt;Grid.Column=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;ColumnDefinitions=&lt;/span&gt;&lt;span class="s"&gt;"*,Auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;DatePicker&lt;/span&gt; &lt;span class="na"&gt;Date=&lt;/span&gt;&lt;span class="s"&gt;"{Binding NewEndDate}"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;TimePicker&lt;/span&gt; &lt;span class="na"&gt;Grid.Column=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;Time=&lt;/span&gt;&lt;span class="s"&gt;"{Binding NewEndTime}"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Grid&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- Buttons --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Grid&lt;/span&gt; &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"4"&lt;/span&gt; &lt;span class="na"&gt;Grid.ColumnSpan=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt; &lt;span class="na"&gt;ColumnDefinitions=&lt;/span&gt;&lt;span class="s"&gt;"*,Auto,Auto"&lt;/span&gt; &lt;span class="na"&gt;ColumnSpacing=&lt;/span&gt;&lt;span class="s"&gt;"8"&lt;/span&gt; &lt;span class="na"&gt;Margin=&lt;/span&gt;&lt;span class="s"&gt;"0,8,0,0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Grid.Column=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;Grid.Column=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Cancel"&lt;/span&gt; &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"{Binding CancelAddCommand}"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;Grid.Column=&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;Button Grid.Column="&lt;/span&gt;&lt;span class="err"&gt;2"&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Save"&lt;/span&gt; &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"{Binding SaveAddCommand}"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Grid&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/Grid&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Border&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Grid&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a Scheduler cell is tapped, you can capture the date and time, pre‑populate the fields, and display the popup using the code example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnSchedulerTapped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SchedulerTappedEventArgs&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Element&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;SchedulerElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SchedulerCell&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;VM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewStartDate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;VM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewStartTime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TimeOfDay&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;VM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEndDate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;VM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEndTime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TimeOfDay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;VM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewSubject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;VM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SelectedRecurrence&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RecurrenceType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;VM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsAddPopupVisible&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we save the new appointment to the existing appointment list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SaveAppointment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NewStartDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;NewStartTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NewEndDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;NewEndTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;appt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;SchedulerAppointment&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Subject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NewSubject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"New Event"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;NewSubject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;StartTime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;EndTime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// &lt;/span&gt;
    &lt;span class="n"&gt;appt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reminders&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ObservableCollection&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SchedulerReminder&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;SchedulerReminder&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;TimeBeforeStart&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="n"&gt;Appointments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;appt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;IsAddPopupVisible&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Set appointment reminders in the .NET MAUI Scheduler
&lt;/h2&gt;

&lt;p&gt;To trigger a reminder before an event starts, set the &lt;a href="https://help.syncfusion.com/cr/maui/Syncfusion.Maui.Scheduler.SchedulerReminder.html#Syncfusion_Maui_Scheduler_SchedulerReminder_TimeBeforeStart" rel="noopener noreferrer"&gt;SchedulerReminder.TimeBeforeStart&lt;/a&gt; property when saving the appointment.&lt;/p&gt;

&lt;p&gt;For example, setting it to 15 minutes ensures the &lt;a href="https://help.syncfusion.com/cr/maui/Syncfusion.Maui.Scheduler.SfScheduler.html?tabs=tabid-41%2Ctabid-65%2Ctabid-6%2Ctabid-22%2Ctabid-43%2Ctabid-32%2Ctabid-24%2Ctabid-69%2Ctabid-35%2Ctabid-28%2Ctabid-13%2Ctabid-67%2Ctabid-8%2Ctabid-19%2Ctabid-16%2Ctabid-39%2Ctabid-62%2Ctabid-46%2Ctabid-30%2Ctabid-10%2Ctabid-71%2Ctabid-48%2Ctabid-37%2Ctabid-26%2Ctabid-4#Syncfusion_Maui_Scheduler_SfScheduler_ReminderAlertOpening" rel="noopener noreferrer"&gt;ReminderAlertOpening&lt;/a&gt; event fires exactly 15 minutes before the scheduled start time, as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Add a 5-minute reminder (will trigger ReminderAlertOpening)&lt;/span&gt;

&lt;span class="n"&gt;appt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reminders&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ObservableCollection&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SchedulerReminder&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;SchedulerReminder&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;TimeBeforeStart&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;Appointments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;appt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Send an event reminder email using Gmail SMTP
&lt;/h2&gt;

&lt;p&gt;You can deliver reminder emails by configuring Gmail’s SMTP server. This requires enabling Gmail’s security features, generating an app password, and authenticating securely before sending the message.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4.1: Enable two-step verification in Gmail
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sign in to your Gmail account.&lt;/li&gt;
&lt;li&gt;Go to Google account settings → security.&lt;/li&gt;
&lt;li&gt;Turn on &lt;strong&gt;2-step verification&lt;/strong&gt; and complete the verification steps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refer to the following image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FEnabling-2-Step-Verification-in-Gmail.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FEnabling-2-Step-Verification-in-Gmail.png" alt="Enabling 2-step verification in Gmail" width="431" height="217"&gt;&lt;/a&gt;&lt;br&gt;Enabling 2-step verification in Gmail
  &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4.2: Generate an app password
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;After enabling 2-step verification, return to &lt;strong&gt;Security.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Signing in to Google&lt;/strong&gt;, click &lt;strong&gt;App Passwords&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select the app type (e.g., &lt;strong&gt;Mail&lt;/strong&gt;) and device (e.g., &lt;strong&gt;Windows Computer&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Generate&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FGenerating-a-Gmail-app-password-for-SMTP-authentication.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FGenerating-a-Gmail-app-password-for-SMTP-authentication.png" alt="Generating a Gmail app password for SMTP authentication" width="471" height="401"&gt;&lt;/a&gt;&lt;br&gt;Generating a Gmail app password for SMTP authentication
  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copy the 16-character app password shown in the popup. This password replaces your regular Gmail password for SMTP authentication.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2Fimage003.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2Fimage003.png" alt="Replacing a Gmail app password for SMTP authentication" width="445" height="375"&gt;&lt;/a&gt;&lt;br&gt;Replacing a Gmail app password for SMTP authentication
  &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4.3: Add SMTP credentials and send the email
&lt;/h3&gt;

&lt;p&gt;Define your Gmail address as &lt;strong&gt;SmtpUser&lt;/strong&gt; and use the generated app password for authentication. Then implement the &lt;strong&gt;SendEmail&lt;/strong&gt; method to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connect securely to Gmail’s SMTP server (smtp.gmail.com on port 587) with TLS enabled.&lt;/li&gt;
&lt;li&gt;Authenticate using the Gmail address and app password.&lt;/li&gt;
&lt;li&gt;Create a MailMessage with &lt;strong&gt;From&lt;/strong&gt;, &lt;strong&gt;To&lt;/strong&gt;, &lt;strong&gt;Subject&lt;/strong&gt;, and &lt;strong&gt;Body&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Attempt to send the email and catche any exceptions to log an error message if sending fails.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s how you can do it in code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Net&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Net.Mail&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Replace with your Gmail and app password&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;SmtpUser&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"your_address@gmail.com"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;SmtpAppPassword&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"your_app_password"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;smtp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SmtpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"smtp.gmail.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;587&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; 
       &lt;span class="n"&gt;EnableSsl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
       &lt;span class="n"&gt;Credentials&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NetworkCredential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SmtpUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SmtpAppPassword&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MailMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SmtpUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; 
       &lt;span class="n"&gt;IsBodyHtml&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;smtp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Email sent successfully!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Error sending email: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4.4: Send the email when the reminder is triggered
&lt;/h3&gt;

&lt;p&gt;Invoke the &lt;strong&gt;SendEmail&lt;/strong&gt; method when the reminder event is triggered. Pass the recipient’s email address, the event subject, and a message that includes the event’s start time as shown in the code example below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Send email notification&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnReminderAlertOpening&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ReminderAlertOpeningEventArgs&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;appt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reminders&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Appointment&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nf"&gt;SendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"recipient@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;$"Reminder: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;appt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;$"Your event starts at &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;appt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Show reminders with toast notifications
&lt;/h2&gt;

&lt;p&gt;When an event reminder becomes due, you can display a native toast notification on the user’s device. This is handled by listening to the Scheduler’s &lt;code&gt;ReminderAlertOpening&lt;/code&gt; event and invoking a cross-platform notification service &lt;code&gt;(INotificationService)&lt;/code&gt; that abstracts platform-specific logic. The interface keeps your UI code clean, and platform-specific implementations handle their own toast notification using native APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Listen to the reminder event
&lt;/h3&gt;

&lt;p&gt;When the reminder event triggers, retrieve the appointment details from the event arguments, create a notification message with the subject and start time, and call the notification service.&lt;/p&gt;

&lt;p&gt;Try this in your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnReminderAlertOpening&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ReminderAlertOpeningEventArgs&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;appt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reminders&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Appointment&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;_notifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ShowNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Reminder"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;$"Upcoming: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;appt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\nStarts at &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;appt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Define a cross-platform notification interface
&lt;/h3&gt;

&lt;p&gt;Next, create an interface that allows your pages to call a single method, while each platform provides its own implementation for showing notifications.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Event_Reminder.Services&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;INotificationService&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ShowNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2.1: Windows toast notification implementation
&lt;/h3&gt;

&lt;p&gt;On Windows, the notification service &lt;code&gt;(WindowsNotificationService)&lt;/code&gt; converts the interface call into a native Windows toast notification. It uses &lt;code&gt;AppNotificationBuilder&lt;/code&gt; to build the notification and &lt;code&gt;AppNotificationManager&lt;/code&gt;to display it. Your page simply calls &lt;code&gt;ShowNotification&lt;/code&gt; while the service creates the banner and places it in the Action Center using the Windows notification APIs.&lt;/p&gt;

&lt;p&gt;Implementation example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#if WINDOWS
&lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Windows.AppNotifications&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Windows.AppNotifications.Builder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Event_Reminder.Services&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WindowsNotificationService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;INotificationService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ShowNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;AppNotificationBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetDuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppNotificationDuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Short&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;AppNotificationManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, register the Windows notification service in &lt;code&gt;MauiProgram.cs&lt;/code&gt; using Dependency Injection:&lt;/p&gt;

&lt;p&gt; MauiProgram.cs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#if WINDOWS
&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;INotificationService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WindowsNotificationService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="cp"&gt;#endif
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2.2: Android toast notification implementation
&lt;/h3&gt;

&lt;p&gt;The&lt;code&gt;AndroidNotificationService&lt;/code&gt; displays native Android notifications by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensuring a notification channel is available on Android 8+ (Oreo).&lt;/li&gt;
&lt;li&gt;Building the notification with a title and expanded message text.&lt;/li&gt;
&lt;li&gt;Setting priority and enabling sound/vibration defaults.&lt;/li&gt;
&lt;li&gt;Wiring a &lt;strong&gt;PendingIntent&lt;/strong&gt; to open your &lt;strong&gt;MainActivity&lt;/strong&gt; when the user taps the banner.&lt;/li&gt;
&lt;li&gt;Finally, displaying the notification using &lt;code&gt;NotificationManagerCompat&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s the complete code block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Android.App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Android.Content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;AndroidX.Core.App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Scheduler_Event_Reminder.Services&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AndroidNotificationService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;INotificationService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ShowNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channelId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"reminder_channel"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Ensure channel exists&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SdkInt&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;Android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BuildVersionCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NotificationManager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSystemService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NotificationService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetNotificationChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotificationChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Reminders"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NotificationImportance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;High&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Reminder notifications"&lt;/span&gt;
                &lt;span class="p"&gt;};&lt;/span&gt;
                &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateNotificationChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Intent for actions&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;intent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MainActivity&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddFlags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActivityFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClearTop&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ActivityFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SingleTop&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pendingIntent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PendingIntent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PendingIntentFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Immutable&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Action buttons&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;replyIntent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MainActivity&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Replace with actual reply handling&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;replyPendingIntent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PendingIntent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;replyIntent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PendingIntentFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Immutable&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;archiveIntent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MainActivity&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Replace with actual archive handling&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;archivePendingIntent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PendingIntent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;archiveIntent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PendingIntentFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Immutable&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Build notification with MessagingStyle&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;NotificationCompat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetSmallIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Drawable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IcDialogInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetContentTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetContentText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;NotificationCompat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BigTextStyle&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;BigText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// Expanded text&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetPriority&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NotificationCompat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PriorityHigh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetDefaults&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;NotificationDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;All&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetCategory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NotificationCompat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CategoryMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetAutoCancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetContentIntent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pendingIntent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;NotificationManagerCompat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;From&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Android 13+ requires &lt;strong&gt;POST_NOTIFICATIONS&lt;/strong&gt; permission while Android 8+ requires a notification channel.&lt;/p&gt;

&lt;p&gt;Then register the Android notification service in &lt;code&gt;MauiProgram.cs&lt;/code&gt;through Dependency Injection:&lt;/p&gt;

&lt;p&gt;MauiProgram.cs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#if ANDROID
&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;INotificationService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AndroidNotificationService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="cp"&gt;#endif
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  AndroidManifest.xml: Request notifications permission (Android 13+)
&lt;/h3&gt;

&lt;p&gt;Add the following permission to your &lt;code&gt;AndroidManifest.xml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;uses-permission&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.permission.POST_NOTIFICATIONS"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  MainActivity.cs: Request permission and create the channel
&lt;/h3&gt;

&lt;p&gt;Android 8+ requires a notification channel, and setting its importance to &lt;strong&gt;High&lt;/strong&gt; enables heads-up banners. In &lt;code&gt;MainActivity.cs&lt;/code&gt;, request the &lt;strong&gt;POST_NOTIFICATIONS&lt;/strong&gt; permission for Android 13+ and create the notification channel for Android 8+, as shown in the code snippet below:&lt;/p&gt;

&lt;p&gt;MainActivity.cs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Android&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Android.App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Android.Content.PM&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Android.OS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Scheduler_Event_Reminder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Theme&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"@style/Maui.SplashTheme"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;MainLauncher&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;LaunchMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LaunchMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SingleTop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ConfigurationChanges&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ConfigChanges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScreenSize&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ConfigChanges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orientation&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ConfigChanges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UiMode&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
                           &lt;span class="n"&gt;ConfigChanges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScreenLayout&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ConfigChanges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SmallestScreenSize&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ConfigChanges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Density&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MauiAppCompatActivity&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OnCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Request POST_NOTIFICATIONS permission for Android 13+&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SdkInt&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;BuildVersionCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tiramisu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;CheckSelfPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Manifest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Permission&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostNotifications&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;Permission&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Granted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;RequestPermissions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Manifest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Permission&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostNotifications&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Create notification channel for heads-up notifications (Android 8+)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SdkInt&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;BuildVersionCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channelId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"reminder_channel"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channelName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Reminders"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotificationChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;channelName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NotificationImportance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;High&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Reminder notifications"&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NotificationManager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;GetSystemService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NotificationService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateNotificationChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2.3: IOS local notification implementation
&lt;/h3&gt;

&lt;p&gt;You can schedule a local notification by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building &lt;strong&gt;&lt;code&gt;UNMutableNotificationContent&lt;/code&gt;&lt;/strong&gt; (title, body, sound).&lt;/li&gt;
&lt;li&gt;Creating a one-second &lt;code&gt;UNTimeIntervalNotificationTrigger&lt;/code&gt; (Apple requires triggers &amp;gt; 0).&lt;/li&gt;
&lt;li&gt;Wrapping it in a &lt;code&gt;UNNotificationRequest&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Lastly, adding it via &lt;code&gt;UNUserNotificationCenter&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You must request notification authorization once at app startup.&lt;/p&gt;

&lt;p&gt;Add this to your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UserNotifications&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Scheduler_Event_Reminder.Services&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;iOSNotificationService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;INotificationService&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ShowNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;UNMutableNotificationContent&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Body&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Sound&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UNNotificationSound&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;

           &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UNTimeIntervalNotificationTrigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UNNotificationRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromIdentifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;UNUserNotificationCenter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddNotificationRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Diagnostics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"[iOS] Notification error: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt;
                    &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Diagnostics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[iOS] Notification scheduled."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, register the iOS notification service in &lt;code&gt;MauiProgram.cs&lt;/code&gt; via dependency injection, shown in the code snippet below.&lt;/p&gt;

&lt;p&gt;MauiProgram.cs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#if IOS
&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;INotificationService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;iOSNotificationService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="cp"&gt;#endif
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2.4: Mac Catalyst local notification implementation
&lt;/h3&gt;

&lt;p&gt;On Mac Catalyst, local notifications follow the same pattern as iOS. Schedule a local notification on Mac Catalyst by creating &lt;code&gt;UNMutableNotificationContent&lt;/code&gt; using a one-second &lt;code&gt;UNTimeIntervalNotificationTrigger&lt;/code&gt;, then wrapping it in a &lt;code&gt;UNUserNotificationCenter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Code example for quick integration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UserNotifications&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Scheduler_Event_Reminder.Services&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MacNotificationService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;INotificationService&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ShowNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;UNMutableNotificationContent&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Body&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Sound&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UNNotificationSound&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UNTimeIntervalNotificationTrigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UNNotificationRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromIdentifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;UNUserNotificationCenter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddNotificationRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Diagnostics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"[Mac Catalyst] Notification error: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then register the Mac Catalyst notification service in &lt;strong&gt;&lt;code&gt;MauiProgram.cs&lt;/code&gt;&lt;/strong&gt; via Dependency Injection:&lt;/p&gt;

&lt;p&gt;MauiProgram.cs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#if MACCATALYST
&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;INotificationService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MacNotificationService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="cp"&gt;#endif
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below is a quick preview of the event reminder feature in action.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2Fimage004.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2Fimage004.gif" alt="Toast notification triggered by an event reminder in the .NET MAUI Scheduler" width="800" height="403"&gt;&lt;/a&gt;&lt;br&gt;Toast notification triggered by an event reminder in the .NET MAUI Scheduler
  &lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub reference
&lt;/h2&gt;

&lt;p&gt;For more details on implementing event reminders with the .NET MAUI Scheduler, refer to the &lt;a href="https://github.com/SyncfusionExamples/.NET_MAUI_Scheduler_Event_Email_Reminder" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why use Syncfusion .NET MAUI Scheduler for reminders&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It supports built-in reminders &lt;code&gt;(EnableReminder=True)&lt;/code&gt; and fires &lt;code&gt;ReminderAlertOpening&lt;/code&gt; so you can trigger emails/toast notifications cross-platform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I bind and display appointments?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Bind the &lt;code&gt;SfScheduler.AppointmentsSource&lt;/code&gt; to an &lt;code&gt;ObservableCollection&lt;/code&gt; in your ViewModel and set the &lt;strong&gt;&lt;code&gt;AllowedViews&lt;/code&gt;&lt;/strong&gt; and View properties as needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I send reminder emails (SMTP) when alerts fire?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, in &lt;code&gt;ReminderAlertOpening&lt;/code&gt;, call &lt;strong&gt;SendEmail&lt;/strong&gt; using &lt;strong&gt;SmtpClient&lt;/strong&gt; to smtp.gmail.com:587 with TLS and Gmail app password authentication.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I display native notifications when a reminder fires?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To do this, handle the &lt;code&gt;ReminderAlertOpening&lt;/code&gt; event and call an &lt;strong&gt;&lt;code&gt;INotificationService&lt;/code&gt;&lt;/strong&gt;. Implement platform-specific services using &lt;code&gt;AppNotificationManager&lt;/code&gt; for Windows, &lt;code&gt;NotificationCompat&lt;/code&gt; for Android, and &lt;code&gt;UNUserNotificationCenter&lt;/code&gt; for iOS and macOS via Dependency Injection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What permissions/config are needed for notifications&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For Android 13 and above, the &lt;strong&gt;POST_NOTIFICATIONS&lt;/strong&gt; permission is needed; for Android 8 and above, create a high-importance notification channel. For iOS and macOS, request user notification authorization once. For Windows, no extra permission is required, just register the service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I prevent missed reminders when the app is backgrounded?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use native notifications per platform, they display even if the app is not foregrounded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I handle recurrence and multiple reminders?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Capture recurrence input in your UI and store with the appointment; for multiple alerts, add multiple &lt;strong&gt;SchedulerReminder&lt;/strong&gt; entries to the appointment’s Reminders collection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I navigate the user when they tap an Android notification?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create an Intent to &lt;strong&gt;MainActivity&lt;/strong&gt; with &lt;code&gt;ActivityFlags.ClearTop | ActivityFlags.SingleTop&lt;/code&gt;, wrap it using &lt;code&gt;PendingIntent.GetActivity(..., PendingIntentFlags.Immutable)&lt;/code&gt;, then set it on &lt;code&gt;NotificationCompat.Builder&lt;/code&gt; via &lt;code&gt;SetContentIntent(pendingIntent)&lt;/code&gt; so tapping the notification opens your app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I manage time zones and all‑day events?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Normalize appointment start and end to the user’s local time zone; for all‑day items, choose a consistent local start (e.g., 9 AM) for reminders to avoid midnight alerts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thank you for reading! Building an event reminder calendar with &lt;a href="https://www.syncfusion.com/maui-controls/maui-scheduler" rel="noopener noreferrer"&gt;Syncfusion .NET MAUI Scheduler&lt;/a&gt; is a powerful way to combine simple event creation with reliable alerts. By adding events through a clean popup, setting reminder lead times, and triggering both native toast notifications and optional SMTP emails, you deliver a smooth, responsive experience across Android, iOS, Windows, and macOS.&lt;/p&gt;

&lt;p&gt;And it doesn’t stop at personal reminders; this same approach works for team calendars, task tracking, and resource planning with custom templates and recurrence. With .NET MAUI’s flexibility and the Scheduler’s rich features, scaling your solution is straightforward.&lt;/p&gt;

&lt;p&gt;If you’re a Syncfusion user, you can download the setup from the &lt;a href="https://www.syncfusion.com/sales/teamlicense" rel="noopener noreferrer"&gt;license and downloads&lt;/a&gt; page. Otherwise, you can download a free &lt;a href="https://www.syncfusion.com/downloads/" rel="noopener noreferrer"&gt;30-day trial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also contact us through our &lt;a href="https://www.syncfusion.com/forums" rel="noopener noreferrer"&gt;support forum&lt;/a&gt;, &lt;a href="https://support.syncfusion.com/" rel="noopener noreferrer"&gt;support portal&lt;/a&gt;, or &lt;a href="https://www.syncfusion.com/feedback" rel="noopener noreferrer"&gt;feedback portal&lt;/a&gt; for queries. We are always happy to assist you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Blogs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/dotnet-maui-weather-forecast-calendar" rel="noopener noreferrer"&gt;Visualize Monthly Weather Forecasts with .NET MAUI Scheduler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/ai-powered-smart-maui-scheduler" rel="noopener noreferrer"&gt;AI-Powered Smart .NET MAUI Scheduler for Easy Appointment Booking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/sync-outlook-calendar-maui-scheduler" rel="noopener noreferrer"&gt;Easily Synchronize Outlook Calendar Events in .NET MAUI Scheduler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/load-maui-scheduler-sqlite-crud" rel="noopener noreferrer"&gt;Easily Load Appointments in .NET MAUI Scheduler with SQLite and Perform CRUD&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally published at &lt;a href="https://www.syncfusion.com/blogs/post/email-toast-reminders-maui-scheduler" rel="noopener noreferrer"&gt;Syncfusion.com.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>netmaui</category>
      <category>androiddevelopment</category>
      <category>calendar</category>
      <category>crossplatformui</category>
    </item>
    <item>
      <title>Why Microsoft Office Automation Is Unsafe on Servers (and the Right .NET Alternative)</title>
      <dc:creator>Phinter Atieno</dc:creator>
      <pubDate>Tue, 24 Feb 2026 15:30:49 +0000</pubDate>
      <link>https://forem.com/syncfusion/why-microsoft-office-automation-is-unsafe-on-servers-and-the-right-net-alternative-4d9j</link>
      <guid>https://forem.com/syncfusion/why-microsoft-office-automation-is-unsafe-on-servers-and-the-right-net-alternative-4d9j</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Many teams still rely on Microsoft Office Automation to generate documents on servers, but it quickly becomes unstable in modern server and cloud environments. Server-safe document generation uses headless, thread-safe libraries that run reliably in web apps, Docker, Linux, and cloud. Learn the risks of Office Automation, what “server-safe” actually means, and how Syncfusion Document SDK can replace Interop with managed .NET APIs.&lt;/p&gt;

&lt;p&gt;Automated document generation powers invoices, statements, reports, dashboards, and customer communications. For years, many teams used &lt;strong&gt;Microsoft Office Automation&lt;/strong&gt; to create Word, Excel, and PowerPoint files programmatically. But as businesses move toward modern web, cloud, and container environments, Office Automation simply can’t keep up. It’s slow, unstable on servers, difficult to scale, and introduces serious security and compatibility issues.&lt;/p&gt;

&lt;p&gt;That’s why developers are shifting to server-safe, cloud-ready document processing frameworks built for today’s architecture. The &lt;a href="https://www.syncfusion.com/document-sdk" rel="noopener noreferrer"&gt;Syncfusion&lt;sup&gt;®&lt;/sup&gt; Document SDK&lt;/a&gt; is one of the most reliable alternatives, delivering fast, scalable, and fully automated generation of PDF, Word, Excel, and PowerPoint files &lt;strong&gt;without requiring Microsoft Office&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you’re still using Office Automation in 2026, this is the perfect time to explore a modern, secure, and scalable way to generate documents at enterprise scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Microsoft Office Automation breaks at scale
&lt;/h2&gt;

&lt;p&gt;Microsoft Office applications were not designed for automated or large-scale processing; they often fail to deliver the stability and scalability required for enterprise document generation. Let’s look at the major limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Requires a real user profile&lt;/strong&gt;: Office relies on user-specific settings (registry, fonts, printers, add-ins). Server accounts often don’t have these. Result: initialization failures and “it works on my machine” incidents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Needs an interactive desktop&lt;/strong&gt;: Office displays modal dialogs when issues occur. On servers, these dialogs can’t be dismissed, causing automation to freeze indefinitely and blocking all processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not designed for high‑volume or parallel workloads&lt;/strong&gt;: Microsoft Office is fundamentally single‑threaded and non‑reentrant, meaning it cannot safely run multiple instances or handle parallel operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Installation and self-repair features break automation&lt;/strong&gt;: Office may trigger configuration wizards or “install on first use” screens that block background processes, something servers cannot handle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Creates security risks&lt;/strong&gt;: Office can unintentionally run macros with elevated privileges, expose shared credentials, and increase overall attack surface on backend systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Licensing restrictions&lt;/strong&gt;: Using Office on a server for multiple users may violate licensing terms unless every consuming user is individually licensed, making it impractical for shared services.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What modern, server-safe document generation actually means
&lt;/h2&gt;

&lt;p&gt;Modern, server-safe document generation goes far beyond simple libraries. It refers to server-friendly, cloud-ready technologies, including SDKs, APIs, services, and CLI tools, that can reliably create and manipulate Word, Excel, PowerPoint, and PDF files without requiring Microsoft Office. These solutions are purpose-built for today’s web, microservice, and distributed environments, offering the reliability and performance that Office Automation cannot match. A true modern document‑generation platform includes the following characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Headless execution&lt;/strong&gt;: No Office installed. No COM. No GUI dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thread-safe for high-volume workloads:&lt;/strong&gt; Handle multiple concurrent requests, ideal for REST APIs, background workers, and microservices that process documents at scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-platform compatibility:&lt;/strong&gt; Works on Windows, Linux, and macOS (including Docker/Kubernetes).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High performance and low memory footprint:&lt;/strong&gt; Optimized for speed, stability, and batch operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure by design:&lt;/strong&gt; No macro execution, privileged operations, and uncontrolled dialogs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feature-rich API surface:&lt;/strong&gt; Supports advanced document manipulation, including styling, tables, formulas, charts, images, shapes, sections, and more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By adopting a modern, server‑safe document generation framework, organizations gain reliable, scalable, and secure document automation that meets the needs of cloud‑native and enterprise‑scale applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical alternative: Syncfusion Document SDK (No Microsoft Office required)
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.syncfusion.com/document-sdk" rel="noopener noreferrer"&gt;Syncfusion Document SDK&lt;/a&gt; is a complete, enterprise-grade suite of .NET libraries designed to replace Microsoft Office Automation entirely. With fully managed APIs for creating, editing, and converting, &lt;a href="https://www.syncfusion.com/document-processing/pdf-framework/net" rel="noopener noreferrer"&gt;PDF&lt;/a&gt;, &lt;a href="https://www.syncfusion.com/document-processing/word-framework/net" rel="noopener noreferrer"&gt;Word (DOCX)&lt;/a&gt;, &lt;a href="https://www.syncfusion.com/document-processing/excel-framework/net" rel="noopener noreferrer"&gt;Excel (XLSX)&lt;/a&gt;, and &lt;a href="https://www.syncfusion.com/document-processing/powerpoint-framework/net" rel="noopener noreferrer"&gt;PowerPoint (PPTX)&lt;/a&gt; files, it serves as a true end-to-end solution for report generation, data processing, and document automation.&lt;/p&gt;

&lt;p&gt;Syncfusion’s Document SDK works seamlessly across the entire .NET ecosystem (.NET Core, Blazor, JavaScript, Flutter, WPF, WinForms). It fits naturally into web APIs, serverless functions, microservices, background jobs, desktop utilities, mobile apps, and large-scale cloud deployments.&lt;/p&gt;

&lt;p&gt;Use it when you need consistent output without installing Microsoft Office on servers or containers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Syncfusion PDF Library: Generate and process PDFs in code
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.syncfusion.com/document-sdk/net-pdf-library" rel="noopener noreferrer"&gt;Syncfusion PDF Library&lt;/a&gt; is a server-safe .NET library for creating, editing, converting, and processing PDFs without Adobe Acrobat or Microsoft Office. It includes APIs for generating PDFs, filling forms, adding annotations, applying security, and optimizing files for web, cloud, and enterprise apps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate PDFs from scratch
&lt;/h3&gt;

&lt;p&gt;You can generate complete PDFs entirely in code, adding text, titles, tables, images, lines, and shapes, to automate fully customized documents that suit everyday business workflows like receipts, operational reports, executive summaries, and approval documents.&lt;/p&gt;

&lt;p&gt;The following code example illustrates how to create a PDF from scratch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Create a new PDF document.&lt;/span&gt;
&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;//Add a page to the document.&lt;/span&gt;
&lt;span class="n"&gt;PdfPage&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;//Create PDF graphics for the page.&lt;/span&gt;
&lt;span class="n"&gt;PdfGraphics&lt;/span&gt; &lt;span class="n"&gt;graphics&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Graphics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//Set the standard font.&lt;/span&gt;
&lt;span class="n"&gt;PdfFont&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfStandardFont&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfFontFamily&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Helvetica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;//Draw the text.&lt;/span&gt;
&lt;span class="n"&gt;graphics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DrawString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello World!!!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PdfBrushes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Black&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PointF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;//Save the document.&lt;/span&gt;
&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Output.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;//Close the document.&lt;/span&gt;
&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For more advanced document‑generation patterns, refer to our official &lt;a href="https://help.syncfusion.com/document-processing/pdf/pdf-library/net/create-pdf-file-in-asp-net-core" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate PDFs from templates + data (AcroForms)
&lt;/h3&gt;

&lt;p&gt;Template-based PDF generation is common for invoices, certificates, HR forms, and contracts. With &lt;strong&gt;AcroForms&lt;/strong&gt;, you fill fields programmatically and optionally &lt;strong&gt;flatten&lt;/strong&gt; the form so values become permanent and non-editable. This pattern is useful when you need a consistent layout + data-driven output at high volume.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you’d like to see this workflow in action, try the &lt;strong&gt;AcroForm&lt;/strong&gt; live &lt;a href="https://document.syncfusion.com/demos/pdf/jobapplication#/tailwind" rel="noopener noreferrer"&gt;demo&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Merge PDFs
&lt;/h3&gt;

&lt;p&gt;You can assemble complex deliverables by merging multiple source PDFs into a single file, streamlining long documents by splitting them into logical parts, and enabling collaborative review by adding notes, highlights, stamps, and other annotations.&lt;/p&gt;

&lt;p&gt;The following code example shows the process of merging multiple PDF documents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Creates a PDF document. &lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;finalDoc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfDocument&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="c1"&gt;//Creates a string array of source files to be merged. &lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"file1.pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"file2.pdf"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; 

    &lt;span class="c1"&gt;//Merges PDFDocument. &lt;/span&gt;
    &lt;span class="n"&gt;PdfDocumentBase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;finalDoc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

    &lt;span class="c1"&gt;//Save the document &lt;/span&gt;
    &lt;span class="n"&gt;finalDoc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Output.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Convert Word, Excel, or PowerPoint to PDF
&lt;/h3&gt;

&lt;p&gt;You can produce consistent, server-safe PDFs by converting DOCX, XLSX, and PPTX files directly to PDF, ensuring repeatable output for office documents without relying on Office Automation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Want to convert a Word, Excel, or PowerPoint file to PDF instantly? Use our free &lt;a href="https://www.syncfusion.com/free-pdf-tools/" rel="noopener noreferrer"&gt;Online PDF Tools&lt;/a&gt; to upload your file and get a high-quality PDF in seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate PDFs from images
&lt;/h3&gt;

&lt;p&gt;You can convert one or more images into a neatly paginated PDF so that scanned paperwork, medical imagery, site‑inspection photos, field evidence, or onboarding document scans can be archived and shared as a single, portable file.&lt;/p&gt;

&lt;p&gt;Here’s how you can do it in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Create Document &lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfDocument&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="c1"&gt;//Add new page &lt;/span&gt;
    &lt;span class="n"&gt;PdfPage&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 

    &lt;span class="c1"&gt;//Load a bitmap &lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;FileStream&lt;/span&gt; &lt;span class="n"&gt;imageStream&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;FileStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Autumn Leaves.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FileMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FileAccess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
    &lt;span class="n"&gt;PdfBitmap&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfBitmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imageStream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

    &lt;span class="c1"&gt;//Draw image &lt;/span&gt;
    &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

    &lt;span class="c1"&gt;//Save the PDF &lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Looking for a simple guide to turn images into clean, multi-page PDFs? Check out our image‑to‑PDF &lt;a href="https://help.syncfusion.com/document-processing/pdf/pdf-library/net/working-with-images" rel="noopener noreferrer"&gt;user guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate PDFs from HTML
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.syncfusion.com/document-sdk/net-pdf-library/html-to-pdf" rel="noopener noreferrer"&gt;Syncfusion’s HTML‑to‑PDF converter&lt;/a&gt; transforms any HTML-based interface into a pixel-perfect PDF, while preserving your original layouts, styles, fonts, images, and even JavaScript-rendered content.&lt;/p&gt;

&lt;p&gt;Implementation example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Initialize HTML-to-PDF converter. &lt;/span&gt;
&lt;span class="n"&gt;HtmlToPdfConverter&lt;/span&gt; &lt;span class="n"&gt;htmlConverter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdfConverter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 

&lt;span class="c1"&gt;//Convert URL to PDF &lt;/span&gt;
&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;htmlConverter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.syncfusion.com"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

&lt;span class="c1"&gt;//Save and close the PDF document. &lt;/span&gt;
&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Output.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This converts an HTML page into a PDF, useful for invoices, dashboards, and “print-ready” versions of web views.&lt;/p&gt;

&lt;p&gt;The following image shows the PDF converted from HTML.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FHTML-converted-to-PDF.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FHTML-converted-to-PDF.png" alt="HTML converted to PDF" width="800" height="507"&gt;&lt;/a&gt;&lt;br&gt;HTML converted to PDF
  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Want to quickly check how your web page looks as a PDF? Try the HTML-to-PDF converter live &lt;a href="https://document.syncfusion.com/demos/pdf/htmltopdf#/bootstrap5" rel="noopener noreferrer"&gt;demo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Syncfusion Word Library: Modern DOCX automation made simple
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.syncfusion.com/document-sdk/net-word-library" rel="noopener noreferrer"&gt;Syncfusion Word Library&lt;/a&gt; &lt;strong&gt;(DocIO)&lt;/strong&gt; makes it simple to create, read, edit, and convert Word documents entirely in code without installing Microsoft Word on your machine or server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create DOCX from scratch
&lt;/h3&gt;

&lt;p&gt;Syncfusion allows users to create &lt;a href="https://www.syncfusion.com/document-sdk/net-word-library/create-word-documents" rel="noopener noreferrer"&gt;Word&lt;/a&gt; documents programmatically without using any template. Use the Syncfusion .NET Word Library to build documents step‑by‑step by adding text, headings, tables, or images through code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For more information about creating a Word document from scratch, refer to our official &lt;a href="https://help.syncfusion.com/document-processing/word/word-library/net/getting-started" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Template-based document creation
&lt;/h3&gt;

&lt;p&gt;Create Word documents easily with a template that you design in Microsoft Word.  The layout remains the same, while only the content changes, saving time and avoiding manual editing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mail merge with data
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.syncfusion.com/document-sdk/net-word-library/mail-merge" rel="noopener noreferrer"&gt;Mail merge&lt;/a&gt; helps you design a DOCX template in Word, add placeholders, and then merge data to generate personalized documents in bulk (letters, invoices, certificates).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FDesigning-a-DOCX-template-in-Word-using-mail-merge.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FDesigning-a-DOCX-template-in-Word-using-mail-merge.png" alt="Designing a DOCX template in Word using mail merge&amp;lt;br&amp;gt;
" width="800" height="296"&gt;&lt;/a&gt;&lt;br&gt;Designing a DOCX template in Word using mail merge&lt;br&gt;

  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Want to give it a try? Check our mail merge live &lt;a href="https://document.syncfusion.com/demos/word/nestedmailmerge#/tailwind" rel="noopener noreferrer"&gt;demo&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advanced document elements
&lt;/h3&gt;

&lt;p&gt;Syncfusion .NET Word Library supports more than plain text: tables, images, fields, &lt;a href="https://www.syncfusion.com/document-sdk/net-word-library/bookmark-in-word-document" rel="noopener noreferrer"&gt;bookmarks&lt;/a&gt; and tracked changes, useful when your “document generation” is really “document assembly.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Explore the complete Syncfusion Word Library &lt;a href="https://help.syncfusion.com/document-processing/word/word-library/net/overview" rel="noopener noreferrer"&gt;user guide&lt;/a&gt; to dive deeper into working with tables, images, fields, bookmarks, and tracked changes, all in one place.&lt;/p&gt;

&lt;p&gt;Syncfusion’s .NET Word Library supports conversions from HTML, Markdown (MD), plain text, and RTF to Word documents, and vice versa. The conversion engine preserves structure, formatting, and styles, ensuring clean DOCX output without requiring Microsoft Word.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Want to learn how to convert Word documents into different formats? Check out the full &lt;a href="https://help.syncfusion.com/document-processing/word/word-library/net/conversion" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; for examples and detailed steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Syncfusion Excel Library: Server-safe Spreadsheet generation
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.syncfusion.com/document-sdk/net-excel-library" rel="noopener noreferrer"&gt;Syncfusion Excel Library (XlsIO)&lt;/a&gt; is a .NET library for creating, editing, and converting Excel files (XLS, XLSX) without requiring Microsoft Office. It is fully headless, built using 100% managed code, and optimized for modern workloads, including web APIs, background services, microservices, and cloud deployments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate Excel files with formulas
&lt;/h3&gt;

&lt;p&gt;You can automate the spreadsheet creation with dynamic formulas that calculate values in real time. This is ideal for generating monthly sales reports, financial summaries, KPI sheets, performance dashboards, and any scenario where totals, margins, or business metrics must be computed automatically.&lt;/p&gt;

&lt;p&gt;Below is the code you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExcelEngine&lt;/span&gt; &lt;span class="n"&gt;excelEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ExcelEngine&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;IApplication&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;excelEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Excel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultVersion&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ExcelVersion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Xlsx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IWorkbook&lt;/span&gt; &lt;span class="n"&gt;workbook&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Workbooks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;IWorksheet&lt;/span&gt; &lt;span class="n"&gt;sheet&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;workbook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Worksheets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;//Setting values to the cells&lt;/span&gt;
    &lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Range&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"A1"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Number&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Range&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"B1"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Number&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt; &lt;span class="n"&gt;Formula&lt;/span&gt;
    &lt;span class="c1"&gt;//Setting formula in the cell&lt;/span&gt;
    &lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Range&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"C1"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Formula&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"=SUM(A1,B1)"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;endregion&lt;/span&gt;

    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="n"&gt;Save&lt;/span&gt;
    &lt;span class="c1"&gt;//Saving the workbook&lt;/span&gt;
    &lt;span class="n"&gt;workbook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFullPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Output/Formula.xlsx"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;endregion&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the code, you’ll see this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FSample-Excel-file-generated-using-Syncfusion-Excel-Library.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FSample-Excel-file-generated-using-Syncfusion-Excel-Library.png" alt="Sample Excel file generated using Syncfusion Excel Library" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;Sample Excel file generated using Syncfusion Excel Library
  &lt;/p&gt;

&lt;p&gt;XlsIO also supports charts, pivot tables, and conversions (Excel to PDF/images), which are common “Interop-only” reasons teams get stuck.&lt;/p&gt;

&lt;h3&gt;
  
  
  Import and export data (CSV, JSON)
&lt;/h3&gt;

&lt;p&gt;Import large datasets from CSV (or other delimited files) and convert them into structured Excel workbooks. Export entire workbooks or specific ranges to CSV or JSON for APIs, downstream systems, and archiving. You can also read from and write to databases directly to reduce manual transfers and improve reporting accuracy.&lt;/p&gt;

&lt;p&gt;The following code example converts an Excel workbook to CSV for downstream systems or integrations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Export Excel as CSV &lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExcelEngine&lt;/span&gt; &lt;span class="n"&gt;excelEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ExcelEngine&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt; 
&lt;span class="n"&gt;IApplication&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;excelEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Excel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultVersion&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ExcelVersion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Xlsx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="n"&gt;IWorkbook&lt;/span&gt; &lt;span class="n"&gt;workbook&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Workbooks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFullPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@"Data/InputTemplate.xlsx"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; 

&lt;span class="c1"&gt;//Saving the workbook  &lt;/span&gt;
&lt;span class="n"&gt;workbook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFullPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Output/Sample.csv"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Explore the &lt;a href="https://help.syncfusion.com/document-processing/excel/excel-library/net/overview" rel="noopener noreferrer"&gt;user guide&lt;/a&gt; and run the live &lt;a href="https://document.syncfusion.com/demos/excel/expensesreport#/tailwind" rel="noopener noreferrer"&gt;demos&lt;/a&gt; to see how easily you can build server-friendly Excel workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Syncfusion PowerPoint Library: Generate PPTX (and export) without PowerPoint
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.syncfusion.com/document-sdk/net-powerpoint-library" rel="noopener noreferrer"&gt;Syncfusion PowerPoint Library&lt;/a&gt; makes it easy to generate, edit, and convert PowerPoint presentations entirely in code without installing Microsoft PowerPoint. If your workflow creates slide decks from data (weekly updates, executive summaries, customer reports), PowerPoint automation via Interop is especially brittle on servers.&lt;/p&gt;

&lt;p&gt;A server-safe approach lets you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create PPTX from scratch or from templates.&lt;/li&gt;
&lt;li&gt;Populate slides with text, tables, charts, and images.&lt;/li&gt;
&lt;li&gt;Clone/reorder slides programmatically.&lt;/li&gt;
&lt;li&gt;Export PPTX to PDF or images for sharing and archiving.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is useful when presentations are part of an automated reporting pipeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create PowerPoint presentations (PPTX) programmatically
&lt;/h3&gt;

&lt;p&gt;You can build a presentation from scratch or open an existing file and add &lt;a href="https://www.syncfusion.com/document-sdk/net-powerpoint-library/powerpoint-slides" rel="noopener noreferrer"&gt;slides&lt;/a&gt;, text, &lt;a href="https://www.syncfusion.com/document-sdk/net-powerpoint-library/powerpoint-shapes" rel="noopener noreferrer"&gt;shapes&lt;/a&gt;, &lt;a href="https://www.syncfusion.com/document-sdk/net-powerpoint-library/powerpoint-tables" rel="noopener noreferrer"&gt;tables&lt;/a&gt;, and &lt;a href="https://www.syncfusion.com/document-sdk/net-powerpoint-library/powerpoint-charts" rel="noopener noreferrer"&gt;charts&lt;/a&gt;. You can also fill slides with real-time data and keep formatting consistent across every presentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FCreating-a-simple-PowerPoint-presentation.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FCreating-a-simple-PowerPoint-presentation.png" alt="Creating a simple PowerPoint presentation" width="800" height="467"&gt;&lt;/a&gt;&lt;br&gt;Creating a simple PowerPoint presentation
  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For more information about creating a simple presentation from scratch, refer to this &lt;a href="https://help.syncfusion.com/document-processing/powerpoint/powerpoint-library/net/getting-started" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you need &lt;strong&gt;SmartArtstyle&lt;/strong&gt; diagrams, you can create them using grouped shapes and connectors. This helps you generate clean, structured slide layouts for reports, dashboards, or summaries with consistent formatting. For more information about SmartArt, refer to this &lt;a href="https://help.syncfusion.com/document-processing/powerpoint/powerpoint-library/net/smartart" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Populate template-based slide decks with business data
&lt;/h3&gt;

&lt;p&gt;Use PowerPoint templates that already contain your slide layout and placeholders, then, using .NET PowerPoint Library, fill those placeholders with real business data. Text boxes, tables, numbers, and charts can be updated automatically, making it easy to generate fresh sales reports or monthly review decks without editing slides by hand. For more information, refer to our official &lt;a href="https://help.syncfusion.com/document-processing/powerpoint/powerpoint-library/net/working-with-powerpoint-presentation" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Insert images, media, branding assets
&lt;/h3&gt;

&lt;p&gt;Use the Syncfusion .NET PowerPoint Library to insert images, logos, and other branding assets into slides, and then control their size and placement programmatically to keep presentations visually consistent. For more information, refer to this &lt;a href="https://help.syncfusion.com/document-processing/powerpoint/powerpoint-library/net/working-with-images" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clone, reorder, or modify slide layouts
&lt;/h3&gt;

&lt;p&gt;Syncfusion .NET PowerPoint Library lets you manage &lt;a href="https://www.syncfusion.com/document-sdk/net-powerpoint-library/powerpoint-slides" rel="noopener noreferrer"&gt;slides&lt;/a&gt; easily through code. You can clone existing slides to reuse their layout, reorder slides to adjust the flow of your presentation, or change the slide’s layout when you need a different structure. For more information, refer to this &lt;a href="https://help.syncfusion.com/document-processing/powerpoint/powerpoint-library/net/working-with-slide" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Export PPTX into PDF, images, or handout style output
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.syncfusion.com/document-sdk/net-powerpoint-library" rel="noopener noreferrer"&gt;Syncfusion .NET PowerPoint Library&lt;/a&gt; makes it easy to export your presentations to different formats. You can convert a &lt;a href="https://www.syncfusion.com/document-sdk/net-powerpoint-library/powerpoint-to-pdf-conversion" rel="noopener noreferrer"&gt;PPTX to a PDF&lt;/a&gt; or convert each slide into an &lt;a href="https://www.syncfusion.com/document-sdk/net-powerpoint-library/powerpoint-to-image-conversion" rel="noopener noreferrer"&gt;image&lt;/a&gt; for use in reports, dashboards, or web applications.&lt;/p&gt;

&lt;p&gt;Take a moment to peruse the &lt;a href="https://help.syncfusion.com/document-processing/powerpoint/powerpoint-library/net/getting-started" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;, where you’ll find other options and features, all with accompanying code examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migration from Office Automation: How to transition smoothly
&lt;/h2&gt;

&lt;p&gt;Organizations are moving away from Office Interop because it relies on desktop applications and UI components, making automation unstable and difficult to scale on servers or in the cloud. The &lt;strong&gt;Syncfusion Document SDK&lt;/strong&gt; offers a modern, cross-platform, and reliable alternative.&lt;/p&gt;

&lt;p&gt;You can map your existing VBA or Interop workflows directly to Syncfusion APIs, Word tasks to &lt;strong&gt;DocIO&lt;/strong&gt;, Excel tasks to &lt;strong&gt;XlsIO&lt;/strong&gt;, PowerPoint tasks to the &lt;strong&gt;Presentation&lt;/strong&gt; library, and PDF tasks to the &lt;strong&gt;PDF Library&lt;/strong&gt;. Macro-based workflows can be replaced with clean .NET code that runs safely in any environment.&lt;/p&gt;

&lt;p&gt;Looking for the simplest way to move your Office Automation workflows to a modern, server-safe solution? Read the Office Automation migration &lt;a href="https://help.syncfusion.com/document-processing/word/word-library/net/faqs/migration-from-microsoft-office-automation-to-docio" rel="noopener noreferrer"&gt;guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking for a simpler, ready‑to‑deploy option for document processing?
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://hub.docker.com/r/syncfusion/document-processing-apis" rel="noopener noreferrer"&gt;Syncfusion Document Processing Web API&lt;/a&gt; is also available as a ready-to-deploy Docker image, providing a fully preconfigured, portable, and easily scalable environment for document conversion and PDF processing with minimal setup. It’s a cost-effective option because it reduces setup time, minimizes maintenance effort, and eliminates the need for complex infrastructure. And since you host the Web API in your own environment, you can apply your own security standards, authentication rules, and network controls, making your deployment even more secure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Ready to set it up quickly? View the &lt;a href="https://help.syncfusion.com/document-processing/web-apis/docker-image-hosting-guide" rel="noopener noreferrer"&gt;hosting guide&lt;/a&gt; for complete setup instructions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does a single Syncfusion license include PDF, Word, Excel, and PowerPoint libraries?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. A Syncfusion Document SDK license includes the full document processing suite, PDF, Word (DOCX), Excel (XLSX), and PowerPoint (PPTX), without requiring separate add-ons or additional purchases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I set up the Document Processing Web API quickly without complex configuration?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Syncfusion provides a ready-to-deploy Docker image for its Document Processing Web APIs, allowing you to start processing PDF, Word, Excel, and PowerPoint files in minutes with minimal setup or manual configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need to pay extra to use the Document Processing API Docker image?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. There is no additional cost for using the Docker image. It uses the same libraries included in your existing Syncfusion Document SDK license, so you can deploy the Web API container without any extra fees.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will the output look the same when switching from Office Automation to the Document SDK?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Document SDK delivers stable, high-fidelity output by preserving layout, fonts, and formatting consistently across operating systems and deployment environments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the Document SDK require external dependencies like Adobe Acrobat or Microsoft Office?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. The Document SDK is a fully headless, standalone engine and does not require Adobe Acrobat, Microsoft Office, or any other external application to create, convert, or process documents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Future-proof document generation
&lt;/h2&gt;

&lt;p&gt;Thank you for reading! Office automation relies on desktop apps, making it unreliable on servers and difficult to scale. This is why modern applications need a safer, faster, and more stable way to generate documents.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.syncfusion.com/document-sdk" rel="noopener noreferrer"&gt;Syncfusion Document SDK&lt;/a&gt; provides a future-proof solution with fully headless, cross-platform libraries for PDF, Word, Excel, and PowerPoint. It works the same on Windows, Linux, and in the cloud and helps you build reliable document workflows without Office Interop.&lt;/p&gt;

&lt;p&gt;If you want to take your document generation to the next level! Try our &lt;a href="https://document.syncfusion.com/#/document-sdk" rel="noopener noreferrer"&gt;Syncfusion Document SDK&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’re a Syncfusion user, you can download the setup from the &lt;a href="https://www.syncfusion.com/sales/pricing" rel="noopener noreferrer"&gt;license and downloads&lt;/a&gt; page. Otherwise, you can download a free &lt;a href="https://www.syncfusion.com/downloads/" rel="noopener noreferrer"&gt;30-day trial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also contact us through our &lt;a href="https://www.syncfusion.com/forums" rel="noopener noreferrer"&gt;support forum&lt;/a&gt;, &lt;a href="https://support.syncfusion.com/" rel="noopener noreferrer"&gt;support portal&lt;/a&gt;, or &lt;a href="https://www.syncfusion.com/feedback" rel="noopener noreferrer"&gt;feedback portal&lt;/a&gt; for queries. We are always happy to assist you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Blogs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/ai-word-document-summarizer-csharp" rel="noopener noreferrer"&gt;AI-Powered Word Document Summarizer in C# With OpenAI GPT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/powerpoint-to-pdf-with-advance-option" rel="noopener noreferrer"&gt;Convert PowerPoint to PDF in C# Using Advanced Formatting Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/document-sdks-2025-vol-3" rel="noopener noreferrer"&gt;Document SDKs 2025 Vol. 3: New Features for PDF, Word, &amp;amp; Excel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/pdf-viewer-docx-editor-2025-vol4" rel="noopener noreferrer"&gt;Essential Studio 2025 Volume 4: What’s New in PDF Viewer and DOCX Editor SDKs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally published at &lt;a href="https://www.syncfusion.com/blogs/post/office-automation-server-alternative" rel="noopener noreferrer"&gt;Syncfusion.com.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>documentsdks</category>
      <category>net</category>
      <category>documenteditor</category>
      <category>documentprocessing</category>
    </item>
    <item>
      <title>ASP.NET Core Security Explained: Modern Authentication, Authorization, and JWT</title>
      <dc:creator>Phinter Atieno</dc:creator>
      <pubDate>Mon, 09 Feb 2026 03:28:57 +0000</pubDate>
      <link>https://forem.com/syncfusion/aspnet-core-security-explained-modern-authentication-authorization-and-jwt-118m</link>
      <guid>https://forem.com/syncfusion/aspnet-core-security-explained-modern-authentication-authorization-and-jwt-118m</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Most ASP.NET Core apps aren’t insecure because Fdevelopers ignore security, but due to subtle, unnoticed issues. This guide shows where things go wrong and how to fix them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why security in ASP.NET Core matters more than ever
&lt;/h2&gt;

&lt;p&gt;Security in ASP.NET has come a long way, from basic authentication in classic ASP.NET to the robust, flexible systems available in ASP.NET Core today. With the .NET 10 release, the core principles remain solid, though it’s always worth checking for updates.&lt;/p&gt;

&lt;p&gt;That’s why locking down your app is non-negotiable. It’s the only way to shield your users, your data, and your reputation from threats that can escalate fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two questions that decide your app’s security
&lt;/h2&gt;

&lt;p&gt;Every secure ASP.NET Core app must answer exactly two questions correctly, every time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Who is the user? (Authentication)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What are they allowed to do? (Authorization)&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you confuse these concepts or blur the distinctions, security holes appear quickly. We’ll walk through both using a realistic scenario, a Blog API with different user roles and permissions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anyone can read posts.&lt;/li&gt;
&lt;li&gt;Logged‑in users can comment.&lt;/li&gt;
&lt;li&gt;Admins can create or delete posts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simple rules. Powerful lessons. Ready to secure your ASP.NET Core app? Let’s dive in and put these principles to work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The basics: Authentication and authorization
&lt;/h2&gt;

&lt;p&gt;Authentication verifies who a user is, like logging in with credentials. Authorization determines what the user can do. ASP.NET Core supports both via middleware and schemes configured in &lt;strong&gt;Program.cs&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
The authentication middleware (&lt;code&gt;UseAuthentication()&lt;/code&gt;) runs early in the pipeline to establish the user’s identity as a &lt;strong&gt;ClaimsPrincipal&lt;/strong&gt;, which authorization then uses to make decisions.&lt;/p&gt;

&lt;p&gt;Building a solid foundation early makes everything smoother. With that groundwork in mind, let’s explore how ASP.NET Core processes requests and the different authentication and authorization types you’ll encounter.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step-by-step flow of involving requests in ASP.NET Core
&lt;/h2&gt;

&lt;p&gt;The following are the steps for authentication and authorization to obtain a protected resource.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;First request (Unauthenticated access attempt)&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;The client sends a request to a protected endpoint (e.g., GET /protected-resource).&lt;/li&gt;
&lt;li&gt;The request contains no valid authentication information (e.g., no cookies, tokens, or headers).&lt;/li&gt;
&lt;li&gt;The server’s authentication middleware &lt;strong&gt;&lt;code&gt;(AuthenticateCoreAsync())&lt;/code&gt;&lt;/strong&gt; runs:&lt;/li&gt;
&lt;li&gt;Calls the handler’s &lt;code&gt;AuthenticateAsync()&lt;/code&gt; method for the scheme(s).&lt;/li&gt;
&lt;li&gt;No valid identity is found, so no &lt;strong&gt;&lt;code&gt;ClaimsPrincipal&lt;/code&gt;&lt;/strong&gt; is created.&lt;/li&gt;
&lt;li&gt;The authorization middleware then checks and fails.&lt;/li&gt;
&lt;li&gt;Since the resource requires authentication, authorization fails.&lt;/li&gt;
&lt;li&gt;Handler then issues a challenge, depending on the scheme:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For&lt;/strong&gt; &lt;strong&gt;APIs/SPAs&lt;/strong&gt;: Often a 401 unauthorized response with &lt;strong&gt;WWW-Authenticate&lt;/strong&gt; header (e.g., “&lt;strong&gt;Bearer&lt;/strong&gt;” for JWT).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For web apps&lt;/strong&gt;: Redirect (302) to a login page (e.g., &lt;strong&gt;/login&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;At this point, no &lt;strong&gt;&lt;code&gt;ClaimsPrincipal&lt;/code&gt;&lt;/strong&gt; exists yet, because the user has not been authenticated.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Second request (login/authentication)&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;The client responds to the earlier challenge by attempting to authenticate:&lt;/li&gt;
&lt;li&gt;Prompts the user for credentials (username/password, etc.).&lt;/li&gt;
&lt;li&gt;Sends a new request, e.g., &lt;strong&gt;POST /login&lt;/strong&gt; or &lt;strong&gt;POST /token&lt;/strong&gt; with those credentials.&lt;/li&gt;
&lt;li&gt;The server’s authentication middleware runs again:&lt;/li&gt;
&lt;li&gt;Handler’s &lt;code&gt;AuthenticateAsync()&lt;/code&gt; validates credentials (e.g., by checking against a database or an external provider).&lt;/li&gt;
&lt;li&gt;If the credentials are valid, the server creates a &lt;code&gt;AuthenticationTicket&lt;/code&gt; containing the user’s claims.&lt;/li&gt;
&lt;li&gt;The handler then calls the &lt;code&gt;SignInAsync()&lt;/code&gt; method to persist the identity (e.g., sets a cookie or issues a JWT token).&lt;/li&gt;
&lt;li&gt;ASP.NET Core sets &lt;code&gt;HttpContext.User&lt;/code&gt; to the newly created &lt;code&gt;ClaimsPrincipal&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The server returns a success status (200 OK) and an authentication artifact (a cookie/token) for the client to use in future requests.&lt;/li&gt;
&lt;li&gt;Now, the &lt;code&gt;ClaimsPrincipal&lt;/code&gt; is established on the server for this session.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subsequent requests (With auth)&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;The client now includes authentication information (e.g., an authorization header with a token or a cookie).&lt;/li&gt;
&lt;li&gt;The authentication middleware authenticates successfully.&lt;/li&gt;
&lt;li&gt;A valid &lt;strong&gt;&lt;code&gt;ClaimsPrincipal&lt;/code&gt;&lt;/strong&gt; is populated immediately.&lt;/li&gt;
&lt;li&gt;Authorization checks pass, then the resource is served.&lt;/li&gt;
&lt;li&gt;No additional login requests needed until the session expires.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The following sequence diagram illustrates the client and server-side flows:&lt;/p&gt;


  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FDetailed-sequence-diagram-showing-the-full-ASP.NET-Core-middleware-pipeline-for-authentication-and-authorization.png" alt="Complete ASP.NET Core authentication and authorization request flow" width="578" height="1070"&gt;Complete ASP.NET Core authentication and authorization request flow
  

&lt;h2&gt;
  
  
  Types of authentication and when to use them
&lt;/h2&gt;

&lt;p&gt;ASP.NET Core supports a variety of authentication policy schemes via middleware. Here’s a grouped overview:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;ASP.NET Core identity:&lt;/strong&gt; It provides a complete, integrated system for managing users, roles, and claims with seamless persistence via &lt;strong&gt;Entity Framework Core.&lt;/strong&gt; It supports modern authentication capabilities, including &lt;strong&gt;passkeys for passwordless login&lt;/strong&gt;, &lt;strong&gt;two-factor authentication&lt;/strong&gt;, and &lt;strong&gt;external logins&lt;/strong&gt;. Use it when you need a full-featured identity system for web apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure authentication:&lt;/strong&gt; It allows you to federate identities with &lt;strong&gt;Microsoft Entra ID&lt;/strong&gt; (formerly Azure AD) using &lt;strong&gt;OpenID Connect (OIDC)&lt;/strong&gt;. This approach provides a &lt;strong&gt;single sign-on (SSO)&lt;/strong&gt; and delivers enterprise-grade security for cloud and hybrid apps. It’s the ideal choice when your app needs to support organizational accounts or integrate with Microsoft 365.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookie authentication:&lt;/strong&gt; It provides a &lt;strong&gt;stateful session&lt;/strong&gt; authentication mechanism for web apps. The server issues an encrypted authentication cookie that stores the user’s identity, and the browser automatically sends it with each request. This allows the server to rebuild the user’s identity across the session. This method works well for traditional MVC apps where session continuity is important.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OIDC web authentication:&lt;/strong&gt; &lt;strong&gt;OpenID Connect (OIDC)&lt;/strong&gt; is used when your web app needs to authenticate users through &lt;strong&gt;external identity providers&lt;/strong&gt; such as Google and Microsoft. The OIDC middleware handles the full flow for you, including redirects, token exchange, and user profile retrieval. It’s the standard for modern federated authentication in web apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JWT Bearer authentication:&lt;/strong&gt; It is designed for &lt;strong&gt;stateless APIs&lt;/strong&gt;. The client sends a &lt;strong&gt;JSON Web Token&lt;/strong&gt; in the authorization header, and the server validates it without maintaining session state. This method is lightweight and ideal for microservices and SPA backends.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Certificate authentication:&lt;/strong&gt; Use client certificates to establish identity via &lt;strong&gt;mutual TLS authentication&lt;/strong&gt;. The server validates the client’s certificate, ensuring strong identity verification. This approach is common in high-security environments like banking or government systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows authentication:&lt;/strong&gt; It is used for &lt;strong&gt;intranet apps&lt;/strong&gt; in which users are a part of an Active Directory domain. It relies on protocols such as &lt;strong&gt;Kerberos&lt;/strong&gt; or &lt;strong&gt;NTLM&lt;/strong&gt; to automatically authenticate users. This method is perfect for internal enterprise apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WS-federation authentication:&lt;/strong&gt; It enables integration with &lt;strong&gt;ADFS&lt;/strong&gt; or &lt;strong&gt;Microsoft Entra ID&lt;/strong&gt; for federated identity. Although it predates modern protocols like OIDC, it remains widely used in legacy enterprise systems. It supports &lt;strong&gt;single sign-on (SSO)&lt;/strong&gt; across multiple apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Social authentication:&lt;/strong&gt; It uses &lt;strong&gt;OAuth&lt;/strong&gt; for providers like Google, Facebook, or GitHub. This allows users to log in with their existing social accounts, improving convenience and reducing password fatigue.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Authentication considerations
&lt;/h2&gt;

&lt;p&gt;Let’s explore the key considerations below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Policy schemes&lt;/strong&gt;: They allow us to combine multiple authentication methods within the same app. For example, we might use &lt;strong&gt;Google OAuth&lt;/strong&gt; to handle sign‑in challenges while using &lt;strong&gt;cookie authentication&lt;/strong&gt; to maintain the session afterward. This approach gives us the flexibility to blend external identity providers with local session management, resulting in a smooth, consistent experience across hybrid authentication flows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mapping, customizing, and transforming claims&lt;/strong&gt;: Standardize user identity information by adjusting or transforming claims within middleware or authorization handlers. This includes mapping external provider claims, such as email or role, into the format your app expects, or adding custom claims required for business logic. These transformations ensure consistent identity data and make it easier to evaluate authorization policies across different identity sources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community OSS options&lt;/strong&gt;: Use open‑source frameworks to handle advanced identity, multi‑tenancy, and authentication needs without building everything yourself. For multi‑tenancy, we can rely on tools like &lt;strong&gt;Orchard Core&lt;/strong&gt;, &lt;strong&gt;ABP Framework&lt;/strong&gt;, or &lt;strong&gt;Finbuckle.MultiTenant&lt;/strong&gt;. For identity and authentication, popular open‑source providers include &lt;strong&gt;Duende IdentityServer&lt;/strong&gt;, &lt;strong&gt;OpenIddict&lt;/strong&gt;, the &lt;strong&gt;FIDO2 .NET Library&lt;/strong&gt;, and &lt;strong&gt;WebAuthn&lt;/strong&gt;. These solutions help us implement standards such as &lt;strong&gt;OAuth2&lt;/strong&gt;, &lt;strong&gt;OpenID Connect&lt;/strong&gt;, and &lt;strong&gt;passwordless authentication&lt;/strong&gt; efficiently and consistently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Factor authentication (MFA)&lt;/strong&gt;: We can enhance account security by verifying a user’s identity with multiple factors (2FA). Common options include &lt;strong&gt;authenticator apps&lt;/strong&gt; (such as Microsoft Authenticator), &lt;strong&gt;passkeys/FIDO2&lt;/strong&gt; for passwordless login, or &lt;strong&gt;SMS-based codes&lt;/strong&gt; for an additional verification step. MFA greatly reduces the likelihood of account compromise and is an essential layer in modern authentication strategies.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Types of authorization (Where most apps quietly fail)
&lt;/h2&gt;

&lt;p&gt;Authorization in ASP.NET Core builds on the &lt;code&gt;ClaimsPrincipal&lt;/code&gt; established during authentication. Each authorization decision relies on the claims contained within that principal, allowing for flexible, fine‑grained access control.&lt;/p&gt;

&lt;p&gt;The following are the primary authorization approaches that leverage the &lt;strong&gt;&lt;code&gt;ClaimsPrincipal&lt;/code&gt;&lt;/strong&gt; model.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Role-based authorization (RBAC)&lt;/strong&gt;: Checks whether the authenticated user belongs to a specific role before granting access. Roles represent pre-defined sets of permissions, such as &lt;strong&gt;Admin&lt;/strong&gt;, &lt;strong&gt;Manager&lt;/strong&gt;, or &lt;strong&gt;User,&lt;/strong&gt; making this approach simple and effective when your app has a clear role hierarch &lt;strong&gt;y&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claims-based authorization&lt;/strong&gt;: This method evaluates specific claims attached to a user’s identity to decide what they can access. Claims are simple key-value attributes representing user details (e.g., “CanComment = true” in our Blog API, enabling commenting privileges). This approach provides more precise and flexible control than basic roles, allowing permissions to be tailored to specific attributes and scenarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy-based authorization&lt;/strong&gt;: This approach allows us to define custom authorization policies that combine specific requirements and handlers to enforce complex business rules. For example, in a Blog API, we might enforce a policy requiring a “&lt;strong&gt;&lt;code&gt;CanComment = true&lt;/code&gt;&lt;/strong&gt;” claim plus a minimum age check via a custom handler for commenting eligibility. It offers high flexibility, making it ideal for advanced scenarios such as external validations, multi‑step checks, or conditional access logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource-based authorization&lt;/strong&gt;: This method performs authorization checks directly against a specific resource, usually within controllers or services. For example, in a Blog API, you can use &lt;strong&gt;IAuthorizationService&lt;/strong&gt; to confirm that the authenticated user owns a post before allowing it to be deleted. This approach is especially effective when permissions depend on resource attributes, such as ownership, rather than general roles or claims.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;View-based authorization&lt;/strong&gt;: This approach applies authorization rules directly in the UI layer, allowing Razor or Blazor views to show or hide components based on the user’s permissions. For example, in a Blog API’s Blazor frontend, you could use the &lt;code&gt;AuthorizeView&lt;/code&gt; component to display a “&lt;strong&gt;Delete Post&lt;/strong&gt;” button only to admins. This improves usability by tailoring the interface to each user and preventing sensitive actions from appearing to unauthorized users.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Authorization considerations
&lt;/h2&gt;

&lt;p&gt;The following considerations strengthen our overall authorization model and prepare the foundation for more advanced scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Authorization policy providers&lt;/strong&gt;: Dynamic policy loading. Use this when a large range of policies is needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limit identity by scheme:&lt;/strong&gt; Use scheme-specific identities when multiple authentication schemes are configured. This provides secure isolation for each scheme and improves code readability and maintainability by clearly indicating which scheme applies to each resource.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customize the behavior of AuthorizationMiddleware&lt;/strong&gt;: Override the default behavior of ASP.NET Core’s AuthorizationMiddleware to handle authorization failures in a custom way. Instead of simply returning a 403 or redirecting to a login page, we can return custom responses (e.g., JSON error messages for APIs), log additional details, or trigger specific workflows. This flexibility is useful for tailoring the user experience and meeting app-specific requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency injection in requirement handlers&lt;/strong&gt;: ASP.NET Core lets us inject services directly into custom authorization requirement handlers. This allows us to access app services, such as databases, logging, and external APIs, while evaluating authorization logic. Using dependency injection creates modular, testable, and maintainable handlers without hardcoding dependencies.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Deep dive: JWT Bearer authentication with policy-based authorization in ASP.NET Core Web API
&lt;/h2&gt;

&lt;p&gt;Let’s build a Blog API with anonymous reads, authenticated comments, and admin posts. The API uses JWT for stateless authentication and policy-based authorization for flexible rules (e.g., age checks or custom logic). This approach scales well for modern APIs.&lt;/p&gt;

&lt;p&gt;If you’re new to creating a minimal API with ASP.NET Core, review the basics in the &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/tutorials/min-web-api?view=aspnetcore-10.0&amp;amp;tabs=visual-studio" rel="noopener noreferrer"&gt;guide&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Setup (Program.cs)
&lt;/h3&gt;

&lt;p&gt;Install the following packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Microsoft.AspNetCore.Authentication.JwtBearer.&lt;/li&gt;
&lt;li&gt;Microsoft.AspNetCore.Identity.EntityFrameworkCore.&lt;/li&gt;
&lt;li&gt;Microsoft.EntityFrameworkCore.SqlServer.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Authentication.JwtBearer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Authorization&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Identity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Identity.EntityFrameworkCore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.EntityFrameworkCore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.IdentityModel.Tokens&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.IdentityModel.Tokens.Jwt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Security.Claims&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Text.Json.Serialization&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configure&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AspNetCore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JsonOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SerializerOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PropertyNameCaseInsensitive&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApplicationDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSqlServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetConnectionString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DefaultConnection"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddIdentity&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IdentityUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IdentityRole&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddEntityFrameworkStores&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApplicationDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDefaultTokenProviders&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// JWT Authentication&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;jwtSettings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"JwtSettings"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAuthentication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JwtBearerDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationScheme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddJwtBearer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TokenValidationParameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TokenValidationParameters&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;ValidateIssuer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ValidIssuer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jwtSettings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Issuer"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;ValidateAudience&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ValidAudience&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jwtSettings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Audience"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;ValidateLifetime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ClockSkew&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Zero&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// stricter expiration&lt;/span&gt;
            &lt;span class="n"&gt;IssuerSigningKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SymmetricSecurityKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jwtSettings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Key"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Policy-Based Authorization&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAuthorization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AdminPolicy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;policy&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RequireRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Admin"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CommentPolicy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;policy&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RequireClaim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CanComment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Requirements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MinimumAgeRequirement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Custom requirement&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IAuthorizationHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MinimumAgeHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDevelopment&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapOpenApi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthentication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseHttpsRedirection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;//Add Endpoints here&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Custom requirement/handler
&lt;/h3&gt;

&lt;p&gt;In a scenario where only users above the age of 18 are eligible to comment on the blog, you can implement a custom authorization requirement and handler to enforce this rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MinimumAgeRequirement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IAuthorizationRequirement&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;MinimumAge&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MinimumAgeRequirement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;minimumAge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MinimumAge&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;minimumAge&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MinimumAgeHandler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AuthorizationHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MinimumAgeRequirement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;HandleRequirementAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AuthorizationHandlerContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MinimumAgeRequirement&lt;/span&gt; &lt;span class="n"&gt;requirement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;dateOfBirthClaim&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindFirst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"DateOfBirth"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dateOfBirthClaim&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;dateOfBirth&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dateOfBirthClaim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Year&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;dateOfBirth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Year&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;requirement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MinimumAge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Succeed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requirement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, create a test user and login Endpoint (Generate JWT) as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/create-test-user"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UserManager&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IdentityUser&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;userManager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;IdentityUser&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;UserName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"test@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"test@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;EmailConfirmed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;userManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"YourStrongPassword123!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Succeeded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;userManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddToRoleAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Admin"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;userManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddClaimAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Claim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CanComment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;userManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddClaimAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Claim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DateOfBirth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"2000-01-01"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Test user created"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BadRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Endpoint for login with JWT generation&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/login"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LoginModel&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SignInManager&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IdentityUser&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;signInManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UserManager&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IdentityUser&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;userManager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;userManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindByEmailAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;signInResult&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;signInManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CheckPasswordSignInAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;signInResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Succeeded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Unauthorized&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Claim&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Claim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Claim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CanComment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRange&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;userManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetRolesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Claim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ClaimTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;dobClaims&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;userManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetClaimsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dobClaims&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;JwtSecurityToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;issuer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;jwtSettings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Issuer"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;audience&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;jwtSettings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Audience"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;expires&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;signingCredentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SigningCredentials&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SymmetricSecurityKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jwtSettings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Key"&lt;/span&gt;&lt;span class="p"&gt;])),&lt;/span&gt; &lt;span class="n"&gt;SecurityAlgorithms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HmacSha256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;JwtSecurityTokenHandler&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;WriteToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Refer to the following image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FSuccessful-POST-request-to-login-on-a-local-ASP.NET-Core-Web-API.-The-response-with-200-OK-and-a-JSON-body-containing-a-long-JWT-in-the-token-field.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FSuccessful-POST-request-to-login-on-a-local-ASP.NET-Core-Web-API.-The-response-with-200-OK-and-a-JSON-body-containing-a-long-JWT-in-the-token-field.png" alt="Successful login to the Blog API using JWT" width="800" height="243"&gt;&lt;/a&gt;&lt;br&gt;Successful login to the Blog API using JWT
  &lt;/p&gt;

&lt;h3&gt;
  
  
  Protected endpoints
&lt;/h3&gt;

&lt;p&gt;Refer to the following code example to configure protected endpoints.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/posts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Public posts"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Anonymous&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/comments"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Add comment"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RequireAuthorization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CommentPolicy"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Policy-Based&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/posts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Create post"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RequireAuthorization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AdminPolicy"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// RBAC via Policy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting the appsettings.json file
&lt;/h3&gt;

&lt;p&gt;The following &lt;code&gt;appsettings.json&lt;/code&gt; configuration centralizes two critical concerns for the application: &lt;strong&gt;JWT authentication settings&lt;/strong&gt; and &lt;strong&gt;database connectivity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;JSON&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JwtSettings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A-Very-Long-Secret-Key-Here-AtLeast-32-Bytes-For-Security&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Issuer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Syncfusion&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Audience&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Syncfusion&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ConnectionStrings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DefaultConnection&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Data Source=YourServerName;Initial Catalog=BlogDb;Integrated Security=True;Encrypt=False&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the client logs in, receives a JWT with claims, and sends it in the Bearer header. ASP.NET Core validates the token, builds the user principal, and evaluates authorization policies for each request.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FSequence-diagram-illustrating-the-JWT-authentication-process-between-Client-and-Server.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FSequence-diagram-illustrating-the-JWT-authentication-process-between-Client-and-Server.png" alt="JWT Bearer authentication flow in ASP.NET Core Web APIs" width="800" height="576"&gt;&lt;/a&gt;&lt;br&gt;JWT Bearer authentication flow in ASP.NET Core Web APIs
  &lt;/p&gt;

&lt;h2&gt;
  
  
  When to use which authentication and authorization approach?
&lt;/h2&gt;

&lt;p&gt;The table below outlines which authentication and authorization methods are most appropriate for different application scenarios.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Category&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Type/Consideration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Scenarios&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;When to Use/Combine&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;td&gt;ASP.NET Core Identity&lt;/td&gt;
&lt;td&gt;User management with DB&lt;/td&gt;
&lt;td&gt;With JWT/Cookie for full stack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;td&gt;Azure/OIDC/Social&lt;/td&gt;
&lt;td&gt;External providers&lt;/td&gt;
&lt;td&gt;Federated logins; combine with Identity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;td&gt;Cookie&lt;/td&gt;
&lt;td&gt;Stateful web apps&lt;/td&gt;
&lt;td&gt;With policies for sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;td&gt;JWT Bearer&lt;/td&gt;
&lt;td&gt;Stateless APIs&lt;/td&gt;
&lt;td&gt;With policy-based for scalability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;td&gt;Certificate/Windows/WS-Fed&lt;/td&gt;
&lt;td&gt;Secure/enterprise&lt;/td&gt;
&lt;td&gt;Intranets; limited combos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication Consideration&lt;/td&gt;
&lt;td&gt;Policy Schemes/MFA&lt;/td&gt;
&lt;td&gt;Multi-scheme/Multi-factor&lt;/td&gt;
&lt;td&gt;Enhance security; OSS for tenants&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authorization&lt;/td&gt;
&lt;td&gt;Role/Claims-Based&lt;/td&gt;
&lt;td&gt;Simple/dynamic access&lt;/td&gt;
&lt;td&gt;Base; combine with policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authorization&lt;/td&gt;
&lt;td&gt;Policy/Resource-Based&lt;/td&gt;
&lt;td&gt;Complex/ownership&lt;/td&gt;
&lt;td&gt;Advanced; with DI/handlers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authorization&lt;/td&gt;
&lt;td&gt;View-Based&lt;/td&gt;
&lt;td&gt;UI control&lt;/td&gt;
&lt;td&gt;Razor; pair with action auth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authorization Consideration&lt;/td&gt;
&lt;td&gt;Providers/Scheme Limits&lt;/td&gt;
&lt;td&gt;Dynamic/custom&lt;/td&gt;
&lt;td&gt;Enterprise; middleware tweaks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Security best practices you should never skip
&lt;/h2&gt;

&lt;p&gt;The following are recommended best practices for building a secure ASP.NET Core application.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enforce HTTPS&lt;/strong&gt;: Prevents token/credential theft by mitigating &lt;strong&gt;man-in-the-middle (MITM)&lt;/strong&gt; attacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use least privilege&lt;/strong&gt;: Limits damage if a token is compromised. Use specific roles or claims instead of “&lt;strong&gt;Admin&lt;/strong&gt;” for everything. Create granular policies (e.g., &lt;code&gt;CanCreatePost&lt;/code&gt;, &lt;strong&gt;&lt;code&gt;CanDeleteOwnComment&lt;/code&gt;&lt;/strong&gt;). Never protect sensitive operations with [Authorize] only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate tokens strictly&lt;/strong&gt;: Prevents forged, expired, or replayed tokens. Use short-lived tokens with a refresh mechanism. Avoid placing sensitive data in claims.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement MFA&lt;/strong&gt;: Passwords alone are not sufficient for secure authentication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store secrets securely (Key Vault)&lt;/strong&gt;: No hardcoded keys in source code. In production, use a secure store such as Azure Key Vault, AWS Secrets Manager, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable audit logging&lt;/strong&gt;: Helps detect breaches and fulfill compliance requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep packages and SDK up to date&lt;/strong&gt;: This will patch known vulnerabilities faster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure cross-origin in Blazor/API hybrids&lt;/strong&gt;: Never store JWT in localStorage (XSS risk). Prefer an HttpOnly cookie with the BFF pattern. If you must use Bearer tokens, use short-lived with the refresh tokens. Always specify allowed origins, and never &lt;strong&gt;&lt;code&gt;AllowAnyOrigin()&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimize performance by caching roles or claims&lt;/strong&gt;: For large apps, cache user roles or claims using &lt;code&gt;IMemoryCache&lt;/code&gt; or similar to reduce database load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extend identity models when needed&lt;/strong&gt;: When using identity, extend &lt;strong&gt;IdentityUser&lt;/strong&gt; or &lt;strong&gt;IdentityRole&lt;/strong&gt; to add custom properties (e.g., add public string Department {get; set;} to the user).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test authentication thoroughly&lt;/strong&gt;: Use tools like Postman to test registration or login with roles. Inspect database tables to confirm proper storage and relationships.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Costly ASP.NET Core security mistakes
&lt;/h2&gt;

&lt;p&gt;Avoid these, and you’re already ahead of most apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trusting JWTs without validation.&lt;/li&gt;
&lt;li&gt;Using roles for complex business rules.&lt;/li&gt;
&lt;li&gt;Storing too many claims in tokens.&lt;/li&gt;
&lt;li&gt;Skipping authorization on background APIs.&lt;/li&gt;
&lt;li&gt;Treating frontend auth as backend security.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion: Build secure ASP.NET Core apps with confidence
&lt;/h2&gt;

&lt;p&gt;Thanks for reading! Securing ASP.NET Core apps today goes far beyond basic login forms or simple role checks. It offers a comprehensive, layered approach, ranging from robust authentication schemes and federated identity to granular policy‑based authorization, custom requirement handlers, and runtime best practices like strict token validation and MFA enforcement. By leveraging features such as ASP.NET Core Identity, JWT Bearer with policy schemes, claims transformation, resource‑based checks, and tools like OpenIddict or Duende, you can build apps that remain resilient against modern threats while staying flexible and scalable.&lt;/p&gt;

&lt;p&gt;Ready to take this further? Whether you’re securing a public‑facing Blazor app, a high‑traffic Web API, or an enterprise microservices environment, start by establishing identity early, layering defenses carefully, and validating relentlessly. Apply these practices incrementally, test with real‑world attack scenarios, and your apps will not only be secure, but they’ll also set the standard for trust in a zero‑trust world.&lt;/p&gt;

&lt;p&gt;Let us know in the comments section which authentication and authorization features you would like explained in the next blog post.&lt;/p&gt;

&lt;p&gt;Once your ASP.NET Core app is secure, building a polished UI shouldn’t slow you down. Syncfusion &lt;a href="https://www.syncfusion.com/aspnet-core-ui-controls" rel="noopener noreferrer"&gt;ASP.NET Core components&lt;/a&gt; help you create secure, role‑aware dashboards and admin screens quickly, so you can focus on logic, not UI boilerplate.&lt;/p&gt;

&lt;p&gt;Try them &lt;a href="https://www.syncfusion.com/downloads/aspnetcore-js2?tag=es-seo-ft-aspnetcore-menu-trial" rel="noopener noreferrer"&gt;free&lt;/a&gt; to accelerate your next secure app.&lt;/p&gt;

&lt;p&gt;You can also reach us via our &lt;a href="https://www.syncfusion.com/forums" rel="noopener noreferrer"&gt;support forum&lt;/a&gt;, &lt;a href="https://support.syncfusion.com/" rel="noopener noreferrer"&gt;support portal&lt;/a&gt;, or &lt;a href="https://www.syncfusion.com/feedback" rel="noopener noreferrer"&gt;feedback portal&lt;/a&gt;. We’d love to hear from you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Blogs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/ai-powered-smart-textarea-aspdotnetcore" rel="noopener noreferrer"&gt;AI-Powered Smart TextArea for ASP.NET Core: Smarter Typing with Intelligent Autocompletion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/aspnet-core-ai-smart-paste-button" rel="noopener noreferrer"&gt;AI-Powered Smart Paste: A Smarter Way to Fill ASP.NET Core Forms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/performance-tuning-in-aspnetcore-2026" rel="noopener noreferrer"&gt;Performance Tuning in ASP.NET Core: Best Practices for 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/whats-new-aspdotnet-core-10-in-net-10" rel="noopener noreferrer"&gt;What’s New in ASP.NET Core 10 for .NET 10: Key Features and Enhancements&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally published at &lt;a href="https://www.syncfusion.com/blogs/post/tips-to-secure-asp-dotnet-core-apps" rel="noopener noreferrer"&gt;Syncfusion.com.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aspnetcore</category>
      <category>net</category>
      <category>development</category>
      <category>security</category>
    </item>
    <item>
      <title>How to Style Summary Rows in a WPF DataGrid for Clearer UI</title>
      <dc:creator>Phinter Atieno</dc:creator>
      <pubDate>Fri, 06 Feb 2026 11:28:24 +0000</pubDate>
      <link>https://forem.com/syncfusion/how-to-style-summary-rows-in-a-wpf-datagrid-for-clearer-ui-3n8e</link>
      <guid>https://forem.com/syncfusion/how-to-style-summary-rows-in-a-wpf-datagrid-for-clearer-ui-3n8e</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Default summary rows in the WPF DataGrid often look generic and make key metrics easy to overlook. This guide shows how to transform table, group, and caption summary rows into visually distinct, readable, and consistent UI elements. You’ll learn when to use implicit versus explicit styles, how to highlight important aggregates, and how to create a maintainable styling strategy that scales across your application.&lt;/p&gt;

&lt;p&gt;Effective data visualization is no longer optional, it’s foundational to modern application design. As datasets grow in size and complexity, users rely on visual cues to quickly interpret totals, averages, and grouped metrics. When these cues are missing, even accurate data can feel overwhelming or hard to trust.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.syncfusion.com/wpf-controls/datagrid" rel="noopener noreferrer"&gt;Syncfusion&lt;sup&gt;®&lt;/sup&gt; WPF DataGrid&lt;/a&gt; offers a powerful data-handling foundation, but its default summary row styles are intentionally neutral. Without customization, critical insights, such as grand totals or group averages, can blend into the grid, reducing clarity and usability.&lt;/p&gt;

&lt;p&gt;By thoughtfully styling summary rows, you can elevate the entire DataGrid experience. Well-designed summary rows guide the user’s eye, reinforce hierarchy, and make important numbers instantly recognizable. In this guide, you’ll learn how to use built-in styling properties, such as background color, typography, and spacing, to create a summary UI that looks intentional, professional, and easy to read.&lt;/p&gt;

&lt;p&gt;We will walk through customization patterns for the following DataGrid elements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Table summary rows and cells.&lt;/li&gt;
&lt;li&gt;Group summary rows and cells.&lt;/li&gt;
&lt;li&gt;Caption summary rows and cells.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best practice:&lt;/strong&gt; Use implicit styles for consistent, app-wide design, and explicit styles when a specific DataGrid requires a unique appearance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customize table summary rows
&lt;/h2&gt;

&lt;p&gt;Table summary rows appear at the top or bottom of the grid and display high-level metrics such as grand totals. Because these values often influence decisions, they should be visually distinguished from regular data rows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Method 1: Style summary rows
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Implicit style for app-wide consistency
&lt;/h3&gt;

&lt;p&gt;By setting the &lt;code&gt;Style.TargetType&lt;/code&gt; property to the &lt;a href="https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Grid.TableSummaryRowControl.html" rel="noopener noreferrer"&gt;TableSummaryRowControl&lt;/a&gt; class, you can define a default appearance for all table summary rows in your application. This allows you to align the grid’s look and feel with your overall design language.&lt;/p&gt;

&lt;p&gt;For the best result, store this style in a shared &lt;strong&gt;ResourceDictionary.&lt;/strong&gt; Doing so ensures consistent styling across the app and reduces repetition when multipe grids use summary rows.&lt;/p&gt;

&lt;p&gt;This approach improves the user experience by making summary rows visually distinct, predictable, and polished.&lt;/p&gt;

&lt;p&gt;Here’s how you can do it in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Style&lt;/span&gt; &lt;span class="na"&gt;TargetType=&lt;/span&gt;&lt;span class="s"&gt;"syncfusion:TableSummaryRowControl"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Background"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Bisque"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontStyle"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Italic"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Foreground"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Red"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explicit styling for a single grid
&lt;/h3&gt;

&lt;p&gt;When you want only a single DataGrid to use a custom table summary row style, define an explicit style and assign it using the &lt;a href="https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Grid.SfDataGrid.html#Syncfusion_UI_Xaml_Grid_SfDataGrid_TableSummaryRowStyle" rel="noopener noreferrer"&gt;TableSummaryRowStyle&lt;/a&gt; property.&lt;/p&gt;

&lt;p&gt;This approach is ideal when a particular grid requires unique branding, visual emphasis, or layout differentiation without affecting other grids in the application.&lt;/p&gt;

&lt;p&gt;For this, refer to this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Style&lt;/span&gt; &lt;span class="na"&gt;TargetType=&lt;/span&gt;&lt;span class="s"&gt;"syncfusion:TableSummaryRowControl"&lt;/span&gt;
       &lt;span class="na"&gt;x:Key=&lt;/span&gt;&lt;span class="s"&gt;"tableSummaryRowStyle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Background"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Bisque"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;syncfusion:SfDataGrid&lt;/span&gt; &lt;span class="na"&gt;x:Name=&lt;/span&gt;&lt;span class="s"&gt;"dataGrid"&lt;/span&gt;  
                       &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Orders}"&lt;/span&gt;
                       &lt;span class="na"&gt;ShowGroupDropArea=&lt;/span&gt;&lt;span class="s"&gt;"True"&lt;/span&gt;
                       &lt;span class="na"&gt;TableSummaryRowStyle=&lt;/span&gt;&lt;span class="s"&gt;"{StaticResource tableSummaryRowStyle}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 
&lt;span class="nt"&gt;&amp;lt;/syncfusion:SfDataGrid&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s what the summary row looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FCustomized-summary-row-1024x491.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FCustomized-summary-row-1024x491.png" alt="Styled table summary row" width="800" height="383"&gt;&lt;/a&gt;&lt;br&gt;Styled table summary row
  &lt;/p&gt;

&lt;h3&gt;
  
  
  Method 2: Style summary cells
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Grid.GridTableSummaryCell.html" rel="noopener noreferrer"&gt;Summary cells&lt;/a&gt; typically display key metrics such as totals, averages, or counts. Applying custom styles to these cells improves readability and helps users quickly identify important values.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implicit styling
&lt;/h3&gt;

&lt;p&gt;You can define implicit styles in XAML to ensure summary cells visually align with your application’s design language.&lt;/p&gt;

&lt;p&gt;Common styling enhancements include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set a &lt;strong&gt;background color&lt;/strong&gt; to visually separate summary cells from regular data rows.&lt;/li&gt;
&lt;li&gt;Apply &lt;strong&gt;bold text&lt;/strong&gt; to emphasize important figures.&lt;/li&gt;
&lt;li&gt;Use a &lt;strong&gt;custom font&lt;/strong&gt; to reflect branding or improve aesthetics.&lt;/li&gt;
&lt;li&gt;Increase the &lt;strong&gt;font size&lt;/strong&gt; to make key data easier to read.&lt;/li&gt;
&lt;li&gt;Change the &lt;strong&gt;text color&lt;/strong&gt; to draw attention.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is the code you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Style&lt;/span&gt; &lt;span class="na"&gt;TargetType=&lt;/span&gt;&lt;span class="s"&gt;"syncfusion:GridTableSummaryCell"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Background"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Beige"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Foreground"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Red"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontSize"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"16"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontFamily"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Congenial Black"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontWeight"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Bold"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explicit styling
&lt;/h3&gt;

&lt;p&gt;To apply the style to a specific DataGrid only, define it with a key and assign it using the &lt;a href="https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Grid.SfDataGrid.html#Syncfusion_UI_Xaml_Grid_SfDataGrid_TableSummaryCellStyle" rel="noopener noreferrer"&gt;TableSummaryCellStyle&lt;/a&gt; property.&lt;/p&gt;

&lt;p&gt;Add the following to your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Style&lt;/span&gt; &lt;span class="na"&gt;TargetType=&lt;/span&gt;&lt;span class="s"&gt;"syncfusion:GridTableSummaryCell"&lt;/span&gt;
       &lt;span class="na"&gt;x:Key=&lt;/span&gt;&lt;span class="s"&gt;"tableSummaryCellStyle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Background"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Beige"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Foreground"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Red"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontSize"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"16"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontFamily"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Congenial Black"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontWeight"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Bold"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;syncfusion:SfDataGrid&lt;/span&gt; &lt;span class="na"&gt;x:Name=&lt;/span&gt;&lt;span class="s"&gt;"dataGrid"&lt;/span&gt;  
                       &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Orders}"&lt;/span&gt;
                       &lt;span class="na"&gt;ShowGroupDropArea=&lt;/span&gt;&lt;span class="s"&gt;"True"&lt;/span&gt;
                       &lt;span class="na"&gt;TableSummaryCellStyle=&lt;/span&gt;&lt;span class="s"&gt;"{StaticResource tableSummaryCellStyle}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 
&lt;span class="nt"&gt;&amp;lt;/syncfusion:SfDataGrid&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the code, you’ll see this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FCustomized-the-summary-cell-1024x494.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FCustomized-the-summary-cell-1024x494.png" alt="Styled table summary cell" width="800" height="385"&gt;&lt;/a&gt;&lt;br&gt;Styled table summary cell
  &lt;/p&gt;

&lt;h2&gt;
  
  
  Customize group summary rows
&lt;/h2&gt;

&lt;p&gt;Group summary rows display aggregated data, such as totals, counts, or averages, for each group of records within the DataGrid. Making these rows visually distinct helps users quickly recognize and interpret important group-level data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Method 1: Style the group summary row
&lt;/h3&gt;

&lt;p&gt;You can customize the appearance of group summary rows by applying a style to the &lt;code&gt;GroupSummaryRowControl&lt;/code&gt; class, which is responsible for rendering group summary sections within the DataGrid.&lt;/p&gt;

&lt;p&gt;By adjusting properties such as &lt;code&gt;Background&lt;/code&gt;, you introduce a clear visual distinction between group summary rows and regular data rows. As a result, group‑level summaries become easier to identify and interpret at a glance.&lt;/p&gt;

&lt;p&gt;The following example demonstrates how to apply this styling in XAML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Style&lt;/span&gt; &lt;span class="na"&gt;TargetType=&lt;/span&gt;&lt;span class="s"&gt;"syncfusion:GroupSummaryRowControl"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Background"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Bisque"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explicit styling
&lt;/h3&gt;

&lt;p&gt;If you want to customize the group summary row for a specific DataGrid only, define the style with an &lt;strong&gt;x:Key&lt;/strong&gt; and apply it using the &lt;a href="https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Grid.SfDataGrid.html#Syncfusion_UI_Xaml_Grid_SfDataGrid_GroupSummaryRowStyle" rel="noopener noreferrer"&gt;GroupSummaryRowStyle&lt;/a&gt; property of the DataGrid. This ensures that the customization affects only the intended grid and does not impact others in your application.&lt;/p&gt;

&lt;p&gt;Try this in your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Style&lt;/span&gt; &lt;span class="na"&gt;TargetType=&lt;/span&gt;&lt;span class="s"&gt;"syncfusion:GroupSummaryRowControl"&lt;/span&gt;
       &lt;span class="na"&gt;x:Key=&lt;/span&gt;&lt;span class="s"&gt;"groupSummaryRowStyle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Background"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Bisque"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;syncfusion:SfDataGrid&lt;/span&gt; &lt;span class="na"&gt;x:Name=&lt;/span&gt;&lt;span class="s"&gt;"dataGrid"&lt;/span&gt;  
                       &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Orders}"&lt;/span&gt;
                       &lt;span class="na"&gt;ShowGroupDropArea=&lt;/span&gt;&lt;span class="s"&gt;"True"&lt;/span&gt;
                       &lt;span class="na"&gt;GroupSummaryRowStyle=&lt;/span&gt;&lt;span class="s"&gt;"{StaticResource groupSummaryRowStyle}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 
&lt;span class="nt"&gt;&amp;lt;/syncfusion:SfDataGrid&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the code, you’ll see this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FCustomized-group-summary-row-1-1024x504.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FCustomized-group-summary-row-1-1024x504.png" alt="Customized group summary row" width="800" height="393"&gt;&lt;/a&gt;&lt;br&gt;Customized group summary row
  &lt;/p&gt;

&lt;h3&gt;
  
  
  Method 2: Style group summary cells
&lt;/h3&gt;

&lt;p&gt;While styling the group summary row improves visibility at a high level, styling the group summary cells allows you to further emphasize individual aggregate values, such as totals, counts, or averages.&lt;/p&gt;

&lt;p&gt;Group summary cells are rendered by the &lt;a href="https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Grid.GridGroupSummaryCell.html" rel="noopener noreferrer"&gt;GridGroupSummaryCell&lt;/a&gt; class. By customizing this class, you can enhance readability and ensure visual consistency with your application’s design language.&lt;/p&gt;

&lt;p&gt;You can adjust the following properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Background:&lt;/strong&gt; Differentiates summary cells from standard data cells&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FontFamily:&lt;/strong&gt; Maintains branding or typographic consistency&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FontSize:&lt;/strong&gt; Improves text readability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Foreground:&lt;/strong&gt; Enhances contrast and visual clarity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FontWeight / FontStyle:&lt;/strong&gt; Adds emphasis to key metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is the code you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Style&lt;/span&gt; &lt;span class="na"&gt;TargetType=&lt;/span&gt;&lt;span class="s"&gt;"syncfusion:GridGroupSummaryCell"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Background"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Beige"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontWeight"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"SemiBold"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Foreground"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"DarkBlue"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontStyle"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Oblique"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontFamily"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Congenial Black"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontSize"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"14"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explicit styling
&lt;/h3&gt;

&lt;p&gt;To apply the group summary cell style to only one &lt;strong&gt;DataGrid&lt;/strong&gt;, define the style with a key and assign it using the &lt;a href="https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Grid.SfDataGrid.html#Syncfusion_UI_Xaml_Grid_SfDataGrid_GroupSummaryCellStyle" rel="noopener noreferrer"&gt;GroupSummaryCellStyle&lt;/a&gt; property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Style&lt;/span&gt; &lt;span class="na"&gt;TargetType=&lt;/span&gt;&lt;span class="s"&gt;"syncfusion:GridGroupSummaryCell"&lt;/span&gt;
       &lt;span class="na"&gt;x:Key=&lt;/span&gt;&lt;span class="s"&gt;"groupSummaryCellStyle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Background"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Beige"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontWeight"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"SemiBold"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Foreground"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"DarkBlue"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontStyle"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Oblique"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontFamily"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Congenial Black"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontSize"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"14"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;syncfusion:SfDataGrid&lt;/span&gt; &lt;span class="na"&gt;x:Name=&lt;/span&gt;&lt;span class="s"&gt;"dataGrid"&lt;/span&gt;  
                       &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Orders}"&lt;/span&gt;
                       &lt;span class="na"&gt;ShowGroupDropArea=&lt;/span&gt;&lt;span class="s"&gt;"True"&lt;/span&gt;
                       &lt;span class="na"&gt;GroupSummaryCellStyle=&lt;/span&gt;&lt;span class="s"&gt;"{StaticResource groupSummaryCellStyle}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 
&lt;span class="nt"&gt;&amp;lt;/syncfusion:SfDataGrid&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FCustomized-group-summary-cell-1024x506.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FCustomized-group-summary-cell-1024x506.png" alt="Customized group summary cell" width="800" height="395"&gt;&lt;/a&gt;&lt;br&gt;Customized group summary cell
  &lt;/p&gt;

&lt;h2&gt;
  
  
  Caption summary row customization
&lt;/h2&gt;

&lt;p&gt;In modern UI development, consistent and intentional styling plays a crucial role in delivering a polished user experience. Within a DataGrid, the caption summary row displays summary or group‑level information above grouped data, serving as an important visual anchor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Method 1: Applying styles to the summary row
&lt;/h3&gt;

&lt;p&gt;You can customize the appearance of caption summary rows by targeting the &lt;a href="https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Grid.CaptionSummaryRowControl.html" rel="noopener noreferrer"&gt;CaptionSummaryRowControl&lt;/a&gt; class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;TargetType&lt;/code&gt;: Specifies that the style should be applied to caption summary row views in the grid.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Background property&lt;/code&gt;: Sets a custom background color for the row, which helps distinguish it from other data rows and improves overall readability.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Style&lt;/span&gt; &lt;span class="na"&gt;TargetType=&lt;/span&gt;&lt;span class="s"&gt;"syncfusion:CaptionSummaryRowControl"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Background"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Bisque"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explicit styling
&lt;/h3&gt;

&lt;p&gt;To limit the caption summary row customization to a specific DataGrid, define the style with a key and assign it using the &lt;a href="https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Grid.SfDataGrid.html#Syncfusion_UI_Xaml_Grid_SfDataGrid_CaptionSummaryRowStyle" rel="noopener noreferrer"&gt;CaptionSummaryRowStyle&lt;/a&gt; property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Style&lt;/span&gt; &lt;span class="na"&gt;TargetType=&lt;/span&gt;&lt;span class="s"&gt;"syncfusion:CaptionSummaryRowControl"&lt;/span&gt;
       &lt;span class="na"&gt;x:Key=&lt;/span&gt;&lt;span class="s"&gt;"captionRowStyle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Background"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Bisque"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;syncfusion:SfDataGrid&lt;/span&gt; &lt;span class="na"&gt;x:Name=&lt;/span&gt;&lt;span class="s"&gt;"dataGrid"&lt;/span&gt;  
                       &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Orders}"&lt;/span&gt;
                       &lt;span class="na"&gt;ShowGroupDropArea=&lt;/span&gt;&lt;span class="s"&gt;"True"&lt;/span&gt;
                       &lt;span class="na"&gt;CaptionSummaryRowStyle=&lt;/span&gt;&lt;span class="s"&gt;"{StaticResource captionRowStyle}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 
&lt;span class="nt"&gt;&amp;lt;/syncfusion:SfDataGrid&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s the expected output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FCustomized-caption-summary-row-1024x505.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FCustomized-caption-summary-row-1024x505.png" alt="Styled caption summary row" width="800" height="394"&gt;&lt;/a&gt;&lt;br&gt;Styled caption summary row
  &lt;/p&gt;

&lt;h3&gt;
  
  
  Method 2: Style group summary cells
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Grid.GridCaptionSummaryCell.html" rel="noopener noreferrer"&gt;GridGroupSummaryCell&lt;/a&gt; class controls how individual summary cells are rendered within grouped rows. You can easily customize their appearance, including background, font family, font size, and foreground color, by defining a style.&lt;/p&gt;

&lt;p&gt;As shown in the code example below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Style&lt;/span&gt; &lt;span class="na"&gt;TargetType=&lt;/span&gt;&lt;span class="s"&gt;"syncfusion:GridCaptionSummaryCell"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Background"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Beige"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontWeight"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Bold"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Foreground"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"DarkBlue"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontStyle"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Italic"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontFamily"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Congenial Black"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontSize"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"14"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explicit styling
&lt;/h3&gt;

&lt;p&gt;To apply the style definition of the &lt;strong&gt;GridCaptionSummaryCell&lt;/strong&gt; class to a particular DataGrid, you can achieve this by setting the &lt;a href="https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Grid.SfDataGrid.html#Syncfusion_UI_Xaml_Grid_SfDataGrid_CaptionSummaryCellStyle" rel="noopener noreferrer"&gt;CaptionSummaryCellStyle&lt;/a&gt; property of the DataGrid, as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Style&lt;/span&gt; &lt;span class="na"&gt;TargetType=&lt;/span&gt;&lt;span class="s"&gt;"syncfusion:GridCaptionSummaryCell"&lt;/span&gt;
       &lt;span class="na"&gt;x:Key=&lt;/span&gt;&lt;span class="s"&gt;"captionSummaryCellStyle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Background"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Beige"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontWeight"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Bold"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Foreground"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"DarkBlue"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontStyle"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Italic"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontFamily"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"Congenial Black"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"FontSize"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"14"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;syncfusion:SfDataGrid&lt;/span&gt; &lt;span class="na"&gt;x:Name=&lt;/span&gt;&lt;span class="s"&gt;"dataGrid"&lt;/span&gt;  
                       &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Orders}"&lt;/span&gt;
                       &lt;span class="na"&gt;ShowGroupDropArea=&lt;/span&gt;&lt;span class="s"&gt;"True"&lt;/span&gt;
                       &lt;span class="na"&gt;CaptionSummaryCellStyle=&lt;/span&gt;&lt;span class="s"&gt;"{StaticResource captionSummaryCellStyle}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 
&lt;span class="nt"&gt;&amp;lt;/syncfusion:SfDataGrid&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FCustomized-group-summary-cell-in-WPF-DataGrid-1024x502.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FCustomized-group-summary-cell-in-WPF-DataGrid-1024x502.png" alt="Customized group summary cell in WPF DataGrid" width="800" height="392"&gt;&lt;/a&gt;&lt;br&gt;Customized group summary cell in WPF DataGrid
  &lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub reference
&lt;/h2&gt;

&lt;p&gt;You can explore the complete code example for styling summary rows on the &lt;a href="https://github.com/SyncfusionExamples/styling-summary-rows-in-wpf-datagrid" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How can I customize the appearance of summary rows in a WPF DataGrid?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can customize the appearance of summary rows by applying a Style with the appropriate target type. Using Style tags allows you to control colors, fonts, borders, and other visual properties of the summary rows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What properties are available for customizing summary rows and cells in a WPF DataGrid?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a WPF DataGrid, you can customize summary rows and cells using several styling properties, including &lt;strong&gt;Background&lt;/strong&gt;, which sets the background color of the row or cell; &lt;strong&gt;Foreground&lt;/strong&gt;, which defines the color of the summary text; &lt;strong&gt;FontFamily&lt;/strong&gt;, used to specify the font type, such as &lt;strong&gt;Congenial Black&lt;/strong&gt;; &lt;strong&gt;FontSize&lt;/strong&gt;, which controls the size of the summary text; &lt;strong&gt;FontWeight&lt;/strong&gt;, enabling styles such as &lt;strong&gt;Bold&lt;/strong&gt;, &lt;strong&gt;Light&lt;/strong&gt;, &lt;strong&gt;Medium&lt;/strong&gt;, or &lt;strong&gt;ExtraBold&lt;/strong&gt;; and &lt;strong&gt;BorderBrush&lt;/strong&gt;, which determines the border color of the summary rows and cells.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How can I customize individual caption summary cells in a WPF DataGrid?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To customize individual caption summary cells, define a Style that targets the GridCaptionSummaryCell element. This allows you to control the appearance of each cell in the caption summary row, including background color, font settings, and text color.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thank you for reading! Customizing the UI style of summary rows in the &lt;a href="https://www.syncfusion.com/wpf-controls/datagrid" rel="noopener noreferrer"&gt;WPF DataGrid&lt;/a&gt; is a straightforward yet powerful way to improve the professionalism and usability of your applications. By using the implicit and explicit styling techniques outlined in this guide, you can ensure your aggregate data is visually appealing and easy to read.&lt;/p&gt;

&lt;p&gt;If you’re a Syncfusion user, you can download the setup from the &lt;a href="https://www.syncfusion.com/account/downloads" rel="noopener noreferrer"&gt;license and downloads&lt;/a&gt; page. Otherwise, you can download a free &lt;a href="https://www.syncfusion.com/downloads/" rel="noopener noreferrer"&gt;30-day trial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also contact us through our &lt;a href="https://www.syncfusion.com/forums" rel="noopener noreferrer"&gt;support forum&lt;/a&gt;, &lt;a href="https://support.syncfusion.com/" rel="noopener noreferrer"&gt;support portal&lt;/a&gt;, or &lt;a href="https://www.syncfusion.com/feedback" rel="noopener noreferrer"&gt;feedback portal&lt;/a&gt; for queries. We are always happy to assist you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Blogs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/summary-calculation-selected-rows-wpf-datagrid" rel="noopener noreferrer"&gt;Introducing Summary Calculation Support for Selected Rows in WPF DataGrid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/checkbox-selector-column-wpf-uwp-datagrid" rel="noopener noreferrer"&gt;New CheckBox Selector Column in the WPF and UWP DataGrid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/natural-language-filter-wpf-datagrid" rel="noopener noreferrer"&gt;AI-Driven Natural Language Filtering in WPF DataGrid for Smarter Data Processing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/wpf-sqlite-crud-datagrid" rel="noopener noreferrer"&gt;Easily Bind SQLite Database and Perform CRUD Actions in WPF DataGrid&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally published at &lt;a href="https://www.syncfusion.com/blogs/post/summary-row-styling-wpf-datagrid" rel="noopener noreferrer"&gt;Syncfusion.com.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>wpf</category>
      <category>net</category>
      <category>datagrid</category>
      <category>desktop</category>
    </item>
    <item>
      <title>Loading Dynamic Data into a .NET MAUI ComboBox with JSON and REST APIs</title>
      <dc:creator>Phinter Atieno</dc:creator>
      <pubDate>Thu, 05 Feb 2026 11:46:06 +0000</pubDate>
      <link>https://forem.com/syncfusion/loading-dynamic-data-into-a-net-maui-combobox-with-json-and-rest-apis-2nf1</link>
      <guid>https://forem.com/syncfusion/loading-dynamic-data-into-a-net-maui-combobox-with-json-and-rest-apis-2nf1</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Dynamic item loading in a .NET MAUI ComboBox is explored through MVVM and async patterns, covering how JSON files and REST APIs supply data to shared binding structures. The discussion includes ObservableCollection updates, XAML bindings, and how the approach adapts as data or API requirements grow.&lt;/p&gt;

&lt;p&gt;Filling a mobile &lt;strong&gt;ComboBox&lt;/strong&gt; with real data can be tricky, &lt;strong&gt;JSON&lt;/strong&gt; shapes can vary, the UI may freeze during loading, and it’s easy to mix up search vs. display fields. Without a solid &lt;strong&gt;MVVM&lt;/strong&gt; setup, bindings can break, and selections can get out of sync.&lt;/p&gt;

&lt;p&gt;In this blog, we’ll show how Syncfusion&lt;sup&gt;®&lt;/sup&gt; &lt;a href="https://www.syncfusion.com/maui-controls/maui-combobox" rel="noopener noreferrer"&gt;.NET MAUI SfComboBox&lt;/a&gt; fixes these issues with clean &lt;strong&gt;MVVM&lt;/strong&gt; data binding and fully async workflows. You’ll get a responsive UI, smooth loading, accurate search and display, and a polished user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you will build
&lt;/h2&gt;

&lt;p&gt;In this guide, you’ll implement the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A ComboBox loading data from a local &lt;strong&gt;JSON&lt;/strong&gt; file.&lt;/li&gt;
&lt;li&gt;A ComboBox loading data from a remote &lt;strong&gt;REST API&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Fully async loading flows that keep your UI buttery-smooth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MVVM&lt;/strong&gt; -driven bindings that stay simple, predictable, and testable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bind a local JSON file to a .NET MAUI ComboBox
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;JSON&lt;/strong&gt; is a lightweight, developer-friendly format widely used for configuration and API data. It stores information using simple key–value pairs and arrays. The &lt;strong&gt;MIME&lt;/strong&gt; type is &lt;strong&gt;application/json&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Below is the sample dataset we’ll use.&lt;/p&gt;

&lt;p&gt;countries.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"United States"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"US"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Canada"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"CA"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Germany"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"DE"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"France"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"FR"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"United Kingdom"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"GB"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"India"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"IN"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Japan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"JP"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Australia"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"AU"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Brazil"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"BR"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"South Africa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"ZA"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We load the &lt;code&gt;countries.json&lt;/code&gt; file directly from the app package, deserialize it into a collection of Country objects, and populate an &lt;code&gt;ObservableCollection&lt;/code&gt; so the ComboBox updates instantly. After loading, the ComboBox displays the country names, and selecting one updates the &lt;strong&gt;Selected&lt;/strong&gt; property and label immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Model &amp;amp; ViewModel (MVVM)
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;MVVM&lt;/strong&gt; pattern keeps your UI logic clean, testable, and easy to maintain. In this example, the Country model represents each &lt;strong&gt;JSON&lt;/strong&gt; record, while &lt;strong&gt;&lt;code&gt;JsonViewModel&lt;/code&gt;&lt;/strong&gt; loads the &lt;code&gt;countries.json&lt;/code&gt; file asynchronously and exposes the data through an &lt;code&gt;ObservableCollection&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;LoadAsync&lt;/code&gt; runs, it opens the bundled &lt;strong&gt;JSON&lt;/strong&gt; file, reads it as text, deserializes it into a list of Country objects (with case-insensitive property mapping), clears any previous items, and repopulates the observable collection. The ComboBox updates automatically as the collection changes.&lt;/p&gt;

&lt;p&gt;Here’s the complete code block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Country&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Code&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JsonViewModel&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ObservableCollection&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Countries&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;LoadAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;FileSystem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OpenAppPackageFileAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"countries.json"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StreamReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadToEndAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;JsonSerializerOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;PropertyNameCaseInsensitive&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;Countries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;Countries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code example below, we include a button to load data, a combo box bound to the Countries list that displays country names and updates the selected item, and a label that shows the selected country’s name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ContentPage.Content&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;VerticalStackLayout&lt;/span&gt; &lt;span class="na"&gt;Padding=&lt;/span&gt;&lt;span class="s"&gt;"50"&lt;/span&gt; &lt;span class="na"&gt;Spacing=&lt;/span&gt;&lt;span class="s"&gt;"12"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Load JSON"&lt;/span&gt; &lt;span class="na"&gt;WidthRequest=&lt;/span&gt;&lt;span class="s"&gt;"320"&lt;/span&gt; &lt;span class="na"&gt;Clicked=&lt;/span&gt;&lt;span class="s"&gt;"OnLoadClicked"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;inputs:SfComboBox&lt;/span&gt; &lt;span class="na"&gt;WidthRequest=&lt;/span&gt;&lt;span class="s"&gt;"320"&lt;/span&gt; &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Countries}"&lt;/span&gt; &lt;span class="na"&gt;DisplayMemberPath=&lt;/span&gt;&lt;span class="s"&gt;"Name"&lt;/span&gt; &lt;span class="na"&gt;TextMemberPath=&lt;/span&gt;&lt;span class="s"&gt;"Name"&lt;/span&gt; &lt;span class="na"&gt;SelectedItem=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Selected, Mode=TwoWay}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Selected.Name, StringFormat='Selected country: {0}'}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/VerticalStackLayout&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ContentPage.Content&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s a preview of this implementation in action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FNET-MAUI-ComboBox-populated-with-local-JSON-data.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FNET-MAUI-ComboBox-populated-with-local-JSON-data.gif" alt=".NET MAUI ComboBox populated with local JSON data" width="800" height="365"&gt;&lt;/a&gt;&lt;br&gt;.NET MAUI ComboBox populated with local JSON data
  &lt;/p&gt;

&lt;h3&gt;
  
  
  Populate the .NET MAUI ComboBox with REST API data
&lt;/h3&gt;

&lt;p&gt;REST APIs let your app interact with remote services over &lt;strong&gt;HTTP&lt;/strong&gt; using standard methods like &lt;strong&gt;GET&lt;/strong&gt;, &lt;strong&gt;POST&lt;/strong&gt;, &lt;strong&gt;PUT/PATCH&lt;/strong&gt;, and &lt;strong&gt;DELETE&lt;/strong&gt;. Responses are usually returned as &lt;strong&gt;JSON&lt;/strong&gt;, making them ideal for ComboBox data.&lt;/p&gt;

&lt;p&gt;You’ll implement two features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load users from a &lt;strong&gt;REST API&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Create a new user (&lt;strong&gt;POST&lt;/strong&gt;) and insert it into the ComboBox&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  REST API ViewModel
&lt;/h3&gt;

&lt;p&gt;It retrieves users from a REST endpoint, sorts them by name, and updates the ComboBox through the &lt;code&gt;LoadAsync&lt;/code&gt; method. It also supports creating a new user. &lt;code&gt;CreateAsync&lt;/code&gt; sends a POST request, receives the created user, and inserts it at the top of the list so the UI refreshes immediately.&lt;/p&gt;

&lt;p&gt;Code snippet to achieve this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RestViewModel&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ObservableCollection&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Users&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;HttpClient&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;HttpClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Timeout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;BaseUrl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://jsonplaceholder.typicode.com/users"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;LoadAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpRequestMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpMethod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BaseUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HttpCompletionOption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseHeadersRead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnsureSuccessStatusCode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;JsonSerializerOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;PropertyNameCaseInsensitive&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAsStreamAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeserializeAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Nothing returned; leave Users empty&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;??=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// avoid null in bindings&lt;/span&gt;
            &lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;       
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;CreateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;newUser&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;UserDto&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PostAsJsonAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newUser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnsureSuccessStatusCode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// JSONPlaceholder returns the created resource with an id&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;created&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFromJsonAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;created&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ScrollView&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Grid&lt;/span&gt; &lt;span class="na"&gt;Padding=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;
          &lt;span class="na"&gt;RowSpacing=&lt;/span&gt;&lt;span class="s"&gt;"12"&lt;/span&gt;
          &lt;span class="na"&gt;ColumnSpacing=&lt;/span&gt;&lt;span class="s"&gt;"12"&lt;/span&gt;
          &lt;span class="na"&gt;RowDefinitions=&lt;/span&gt;&lt;span class="s"&gt;"Auto,Auto"&lt;/span&gt;
          &lt;span class="na"&gt;ColumnDefinitions=&lt;/span&gt;&lt;span class="s"&gt;"*,*"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Load from API"&lt;/span&gt;
                &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;
                &lt;span class="na"&gt;Grid.Column=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;
                &lt;span class="na"&gt;HeightRequest=&lt;/span&gt;&lt;span class="s"&gt;"{OnPlatform Android=56, iOS=52, WinUI=48}"&lt;/span&gt;
                &lt;span class="na"&gt;MinimumHeightRequest=&lt;/span&gt;&lt;span class="s"&gt;"48"&lt;/span&gt;
                &lt;span class="na"&gt;MaximumWidthRequest=&lt;/span&gt;&lt;span class="s"&gt;"320"&lt;/span&gt;
                &lt;span class="na"&gt;HorizontalOptions=&lt;/span&gt;&lt;span class="s"&gt;"Fill"&lt;/span&gt;
                &lt;span class="na"&gt;Clicked=&lt;/span&gt;&lt;span class="s"&gt;"OnLoadClicked"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Create user (POST)"&lt;/span&gt;
                &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;
                &lt;span class="na"&gt;Grid.Column=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;
                &lt;span class="na"&gt;HeightRequest=&lt;/span&gt;&lt;span class="s"&gt;"{OnPlatform Android=56, iOS=52, WinUI=48}"&lt;/span&gt;
                &lt;span class="na"&gt;MinimumHeightRequest=&lt;/span&gt;&lt;span class="s"&gt;"48"&lt;/span&gt;
                &lt;span class="na"&gt;HorizontalOptions=&lt;/span&gt;&lt;span class="s"&gt;"Fill"&lt;/span&gt;
                &lt;span class="na"&gt;MaximumWidthRequest=&lt;/span&gt;&lt;span class="s"&gt;"320"&lt;/span&gt;
                &lt;span class="na"&gt;Clicked=&lt;/span&gt;&lt;span class="s"&gt;"OnCreateClicked"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;inputs:SfComboBox&lt;/span&gt; &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;
                           &lt;span class="na"&gt;Grid.Column=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;
                           &lt;span class="na"&gt;HeightRequest=&lt;/span&gt;&lt;span class="s"&gt;"{OnPlatform Android=56, iOS=52, WinUI=48}"&lt;/span&gt;
                           &lt;span class="na"&gt;MinimumHeightRequest=&lt;/span&gt;&lt;span class="s"&gt;"48"&lt;/span&gt;
                           &lt;span class="na"&gt;HorizontalOptions=&lt;/span&gt;&lt;span class="s"&gt;"Fill"&lt;/span&gt;
                           &lt;span class="na"&gt;MaximumWidthRequest=&lt;/span&gt;&lt;span class="s"&gt;"320"&lt;/span&gt;
                           &lt;span class="na"&gt;ItemsSource=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Users}"&lt;/span&gt;
                           &lt;span class="na"&gt;DisplayMemberPath=&lt;/span&gt;&lt;span class="s"&gt;"Name"&lt;/span&gt;
                           &lt;span class="na"&gt;TextMemberPath=&lt;/span&gt;&lt;span class="s"&gt;"Name"&lt;/span&gt;
                           &lt;span class="na"&gt;Placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Select a user"&lt;/span&gt;
                           &lt;span class="na"&gt;Margin=&lt;/span&gt;&lt;span class="s"&gt;"0,0,0,0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;Entry&lt;/span&gt; &lt;span class="na"&gt;x:Name=&lt;/span&gt;&lt;span class="s"&gt;"NameEntry"&lt;/span&gt;
               &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;
               &lt;span class="na"&gt;Grid.Column=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;
               &lt;span class="na"&gt;HeightRequest=&lt;/span&gt;&lt;span class="s"&gt;"{OnPlatform Android=56, iOS=52, WinUI=48}"&lt;/span&gt;
               &lt;span class="na"&gt;MinimumHeightRequest=&lt;/span&gt;&lt;span class="s"&gt;"48"&lt;/span&gt;
               &lt;span class="na"&gt;HorizontalOptions=&lt;/span&gt;&lt;span class="s"&gt;"Fill"&lt;/span&gt;
               &lt;span class="na"&gt;MaximumWidthRequest=&lt;/span&gt;&lt;span class="s"&gt;"320"&lt;/span&gt;
               &lt;span class="na"&gt;Keyboard=&lt;/span&gt;&lt;span class="s"&gt;"Text"&lt;/span&gt;
               &lt;span class="na"&gt;ReturnType=&lt;/span&gt;&lt;span class="s"&gt;"Done"&lt;/span&gt;
               &lt;span class="na"&gt;ClearButtonVisibility=&lt;/span&gt;&lt;span class="s"&gt;"WhileEditing"&lt;/span&gt;
               &lt;span class="na"&gt;Placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Enter new user name to POST"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Grid&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ScrollView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sample UI provides a Load from API button to fetch users, a ComboBox that lists the results by name, an Entry for adding a new user, and a Create user (POST) button to send the new name to the API and update the list instantly.&lt;/p&gt;

&lt;p&gt;See the implementation in action below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FNET-MAUI-ComboBox-with-REST-APIs.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FNET-MAUI-ComboBox-with-REST-APIs.gif" alt=".NET MAUI ComboBox with REST APIs" width="800" height="385"&gt;&lt;/a&gt;&lt;br&gt;.NET MAUI ComboBox with REST APIs
  &lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub reference
&lt;/h2&gt;

&lt;p&gt;For more details on data binding in .NET MAUI ComboBox, refer to the &lt;a href="https://github.com/SyncfusionExamples/How-to-bind-the-.NET-MAUI-ComboBox-to-various-data-sources-including-arrays-JSON-feeds-and-REST-APIs" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thanks for reading! You’ve now wired the Syncfusion &lt;a href="https://www.syncfusion.com/maui-controls/maui-combobox" rel="noopener noreferrer"&gt;.NET MAUI ComboBox&lt;/a&gt; to both local &lt;strong&gt;JSON&lt;/strong&gt; files and live &lt;strong&gt;REST APIs&lt;/strong&gt; using clean &lt;strong&gt;MVVM&lt;/strong&gt; architecture and fully asynchronous workflows. This approach keeps your UI responsive, your bindings predictable, and your codebase maintainable.&lt;/p&gt;

&lt;p&gt;If you’re a Syncfusion user, you can download the setup from the &lt;a href="https://www.syncfusion.com/account/downloads" rel="noopener noreferrer"&gt;license and downloads&lt;/a&gt; page. Otherwise, you can download a free &lt;a href="https://www.syncfusion.com/downloads/" rel="noopener noreferrer"&gt;30-day trial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also contact us through our &lt;a href="https://www.syncfusion.com/forums" rel="noopener noreferrer"&gt;support forum&lt;/a&gt;, &lt;a href="https://support.syncfusion.com/" rel="noopener noreferrer"&gt;support portal&lt;/a&gt;, or &lt;a href="https://www.syncfusion.com/feedback" rel="noopener noreferrer"&gt;feedback portal&lt;/a&gt; for queries. We are always happy to assist you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Blogs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/multi-step-wizard-dotnet-maui-tab-view" rel="noopener noreferrer"&gt;Building a Gated Multi-Step Wizard in .NET MAUI with Tab View&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/ai-powered-kanban-dotnet-maui" rel="noopener noreferrer"&gt;Automate Task Planning with an AI-Powered Kanban Board in .NET MAUI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/geo-analytics-dashboard-dotnet-maui" rel="noopener noreferrer"&gt;Visualizing Geo-Spatial Data in .NET MAUI with Interactive Charts and Maps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/choose-right-dotnet-maui-picker" rel="noopener noreferrer"&gt;Choosing the Right .NET MAUI Picker: Date, Time &amp;amp; List Selection Made Simple&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally published at &lt;a href="https://www.syncfusion.com/blogs/post/maui-combobox-json-rest-api" rel="noopener noreferrer"&gt;Syncfusion.com.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>netmaui</category>
      <category>combobox</category>
      <category>desktop</category>
      <category>inputcontrols</category>
    </item>
    <item>
      <title>Why Hyperlinks Break in JavaScript PDF Viewers and How to Fix Them</title>
      <dc:creator>Phinter Atieno</dc:creator>
      <pubDate>Thu, 05 Feb 2026 11:04:59 +0000</pubDate>
      <link>https://forem.com/syncfusion/why-hyperlinks-break-in-javascript-pdf-viewers-and-how-to-fix-them-1o93</link>
      <guid>https://forem.com/syncfusion/why-hyperlinks-break-in-javascript-pdf-viewers-and-how-to-fix-them-1o93</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Learn how JavaScript PDF viewers often struggle with hyperlink reliability due to annotation handling, canvas rendering, browser differences, accessibility layers, and complex PDF structures, along with the considerations involved in rectifying these issues in real-world applications.&lt;/p&gt;

&lt;p&gt;Hyperlinks play a vital role in making PDF documents more user-friendly, accessible, and interactive. Whether you’re jumping to a specific section within a file, opening a webpage, or linking to another document, hyperlinks help users navigate content efficiently, especially in lengthy PDFs like manuals, reports, or eBooks.&lt;/p&gt;

&lt;p&gt;But in many web applications, JavaScript-based PDF viewers often fall short when it comes to handling hyperlinks smoothly. Users may encounter broken links, unresponsive clicks, or unexpected behaviour, which can be frustrating and reduce the overall usefulness of the document. This is especially problematic in environments where seamless navigation is expected.&lt;/p&gt;

&lt;p&gt;In this guide, we’ll take a closer look at why hyperlink navigation tends to fail in JavaScript PDF viewers and how &lt;a href="https://www.syncfusion.com/pdf-viewer-sdk/javascript-pdf-viewer" rel="noopener noreferrer"&gt;Syncfusion&lt;sup&gt;®&lt;/sup&gt; PDF Viewer&lt;/a&gt; offers a reliable solution to overcome these challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common hyperlink issues in JavaScript PDF Viewers
&lt;/h2&gt;

&lt;p&gt;Although hyperlinks are crucial in PDFs, many JavaScript-based viewers are unable to handle them consistently. The most frequent problems that developers and users encounter are listed below:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Non-functional links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Links appear clickable but don’t respond due to missing event listeners or incorrect annotation rendering. This issue is commonly discussed in developer forums such as &lt;a href="https://pdfjs.community/t/hyperlinks-not-being-detected-in-pdf-js-viewer/1925" rel="noopener noreferrer"&gt;PDF.js Viewer&lt;/a&gt; and &lt;a href="https://github.com/arkokoley/pdfvuer/issues/50" rel="noopener noreferrer"&gt;Pdfvuer&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Overlapping visual elements may block pointer events, making links unresponsive.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Incorrect navigation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Links may lead to wrong destinations because of parsing errors or poor annotation support. This is a known issue discussed in the &lt;a href="https://github.com/mozilla/pdf.js/issues/7154" rel="noopener noreferrer"&gt;PDF.js GitHub&lt;/a&gt; repository.&lt;/li&gt;
&lt;li&gt;Relative URLs and broken internal references often fail, especially in iframes or multi-source setups.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Canvas rendering limitations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;HTML5  rendering can omit hyperlinks, making them invisible or non-clickable.&lt;/li&gt;
&lt;li&gt;Canvas-based viewers lack accessibility support, preventing screen readers from detecting links.&lt;/li&gt;
&lt;li&gt;For more details and potential workarounds, refer to this Stack Overflow discussion on &lt;a href="https://stackoverflow.com/questions/19953879/links-hyperlinks-into-a-canvas-using-pdf-js" rel="noopener noreferrer"&gt;hyperlinks in canvas&lt;/a&gt; using PDF.js.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Lack of support for internal and external links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Some viewers support only one type of link (internal or external), limiting interactivity.&lt;/li&gt;
&lt;li&gt;Poor visual cues (e.g., missing underlines or hover effects) make links hard to identify and use.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Inconsistent behaviour across browsers and devices
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Link functionality varies across browsers due to differences in rendering engines and event handling.&lt;/li&gt;
&lt;li&gt;On mobile devices, touch gestures may misfire, causing missed or unintended link activations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How Syncfusion JavaScript PDF Viewer handles hyperlink issues
&lt;/h2&gt;

&lt;p&gt;Hyperlinks in PDFs should just work, but in many JavaScript viewers, they don’t. Syncfusion’s JavaScript PDF Viewer changes the game by making link navigation seamless, reliable, and accessible. Here’s how:&lt;/p&gt;

&lt;h3&gt;
  
  
  Smart link detection
&lt;/h3&gt;

&lt;p&gt;Whether it’s a page reference, a web URL, or an email address, Syncfusion automatically detects and renders both internal and external links; no extra setup needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FDetected-internal-and-external-hyperlinks-within-a-PDF.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FDetected-internal-and-external-hyperlinks-within-a-PDF.png" alt="Detected internal and external hyperlinks within a PDF" width="800" height="410"&gt;&lt;/a&gt;&lt;br&gt;Detected internal and external hyperlinks within a PDF
  &lt;/p&gt;

&lt;h3&gt;
  
  
  Instant and interactive navigation
&lt;/h3&gt;

&lt;p&gt;Click a link and go; no delays, no misfires. Internal links jump to the right page, and external ones open in a new tab, keeping the reading flow smooth and engaging.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FInstant-navigation-triggered-by-hyperlink-interaction.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FInstant-navigation-triggered-by-hyperlink-interaction.gif" alt="Instant navigation triggered by hyperlink interaction" width="800" height="425"&gt;&lt;/a&gt;&lt;br&gt;Instant navigation triggered by hyperlink interaction
  &lt;/p&gt;

&lt;h3&gt;
  
  
  No canvas, no compromise
&lt;/h3&gt;

&lt;p&gt;If you’re seeing “&lt;strong&gt;PDF hyperlink is not working&lt;/strong&gt;” in canvas-based viewers, Syncfusion’s DOM-based rendering preserves clickable links and accessibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accurate link interpretation in layered &amp;amp; annotated PDFs
&lt;/h3&gt;

&lt;p&gt;Got nested bookmarks, encoded annotations, or layered content? No problem. Syncfusion accurately interprets and renders hyperlinks, even in the most intricate documents.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consistent across browsers &amp;amp; devices
&lt;/h3&gt;

&lt;p&gt;Chrome, Firefox, Safari, Edge—Syncfusion’s viewer is tested across all major platforms to ensure hyperlinks behave consistently, even on mobile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced hyperlink customization in Syncfusion JavaScript PDF Viewer
&lt;/h2&gt;

&lt;p&gt;Syncfusion JavaScript PDF Viewer enables developers to customize how hyperlinks behave and function precisely. This is especially helpful for online programs where context and user flow are important.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Customizing hyperlink behaviour
&lt;/h3&gt;

&lt;p&gt;Using the &lt;a href="https://ej2.syncfusion.com/javascript/documentation/api/pdfviewer/#hyperlinkopenstate" rel="noopener noreferrer"&gt;hyperlinkOpenState &lt;/a&gt;API, you can precisely control how hyperlinks behave within embedded PDFs. This feature allows you to define whether links should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open in the &lt;strong&gt;same tab&lt;/strong&gt; for seamless navigation,&lt;/li&gt;
&lt;li&gt;Launch in a &lt;strong&gt;new tab&lt;/strong&gt; to preserve the current context, or&lt;/li&gt;
&lt;li&gt;Be &lt;strong&gt;disabled entirely&lt;/strong&gt; to prevent external navigation.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pdfViewer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;height: 100%;width: 100%;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;viewer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PdfViewer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PdfViewer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;viewer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://ej2services.syncfusion.com/production/web-services/api/pdfviewer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;viewer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PDF_Succinctly.pdf&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;viewer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hyperlinkOpenState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NewTab&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;viewer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#pdfViewer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This level of control is particularly valuable in web applications where maintaining user flow and context is critical.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Intercepting hyperlink clicks
&lt;/h3&gt;

&lt;p&gt;To implement custom logic when a hyperlink is clicked, use the &lt;a href="https://ej2.syncfusion.com/javascript/documentation/api/pdfviewer/#hyperlinkclick" rel="noopener noreferrer"&gt;hyperLinkClick &lt;/a&gt;event. This event gives you complete control over the navigation flow. By setting &lt;strong&gt;&lt;code&gt;args.cancel = true&lt;/code&gt;&lt;/strong&gt;, you can intercept and override the default behaviour. This gives you the flexibility to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log link clicks for analytics.&lt;/li&gt;
&lt;li&gt;Show confirmation dialogs before navigation.&lt;/li&gt;
&lt;li&gt;Prevent navigation based on user roles or permissions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may refer to the official &lt;a href="https://ej2.syncfusion.com/javascript/documentation/api/pdfviewer/index-default#hyperlinkclick" rel="noopener noreferrer"&gt;API documentation&lt;/a&gt; for detailed information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best practices for developers
&lt;/h2&gt;

&lt;p&gt;To ensure reliable hyperlink functionality in JavaScript PDF viewers, developers should follow these universal best practices:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Enable hyperlink features in the PDF Viewer
&lt;/h3&gt;

&lt;p&gt;Most PDF viewers offer configuration options to enable or enhance hyperlink support. Check the documentation for flags like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;enableHyperlink&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;linkAnnotationEnabled&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;openExternalLinksInNewTab&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These settings help control how links behave within the viewer.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Use clear and accessible link design
&lt;/h3&gt;

&lt;p&gt;Design hyperlinks to be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visually distinct (e.g., underlined or colored).&lt;/li&gt;
&lt;li&gt;Descriptive (e.g., “Download Report” instead of “Click here”).&lt;/li&gt;
&lt;li&gt;Keyboard and screen-reader friendly, improving accessibility for all users.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Validate external URLs
&lt;/h3&gt;

&lt;p&gt;When linking to external resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure URLs are valid and secure (use HTTPS).&lt;/li&gt;
&lt;li&gt;Avoid hardcoding links that may break over time.&lt;/li&gt;
&lt;li&gt;Consider opening links in a new tab to preserve the user’s session.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does Syncfusion JavaScript PDF Viewer support both internal and external links?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Syncfusion PDF Viewer supports both internal and external hyperlinks without extra configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is email and web links supported?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Syncfusion PDF Viewer automatically detects web URLs and email links without additional configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I control how links open in Syncfusion PDF Viewer?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. You can control whether links open in the same tab, new tab, or are disabled using the &lt;a href="https://ej2.syncfusion.com/javascript/documentation/api/pdfviewer/#hyperlinkopenstate" rel="noopener noreferrer"&gt;hyperlinkOpenState&lt;/a&gt; setting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can developers customize hyperlink click behavior?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. The &lt;a href="https://ej2.syncfusion.com/javascript/documentation/api/pdfviewer/#hyperlinkclick" rel="noopener noreferrer"&gt;hyperLinkClick&lt;/a&gt; event lets developers track, intercept, or prevent navigation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What types of navigation are supported in Syncfusion JavaScript PDF Viewer?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Syncfusion PDF Viewer supports Page, Bookmark, Thumbnail, Table of content and Hyperlink navigations for seamless document interaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thank you for reading! Hyperlinks are essential for creating interactive and accessible PDF documents, especially in web-based applications. However, many JavaScript PDF viewers struggle to render hyperlinks consistently due to limitations in canvas-based rendering, browser inconsistencies, and a lack of support for complex PDF structures.&lt;/p&gt;

&lt;p&gt;By following best practices during PDF creation and viewer setup, developers can significantly improve the reliability and usability of PDF hyperlink navigation. For those looking for a dependable and feature-rich solution, &lt;a href="https://www.syncfusion.com/pdf-viewer-sdk/javascript-pdf-viewer" rel="noopener noreferrer"&gt;Syncfusion JavaScript PDF Viewer&lt;/a&gt; offers accurate link detection, smooth navigation, and consistent performance across browsers—all without the limitations of canvas rendering. If your application depends on reliable hyperlink navigation in PDFs, Syncfusion is a smart, scalable choice.&lt;/p&gt;

&lt;p&gt;Explore our JavaScript PDF Viewer &lt;a href="https://help.syncfusion.com/document-processing/pdf/pdf-viewer/javascript-es5/getting-started" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; to dive deeper into its technical capabilities and see how it can streamline document rendering and interaction in your web apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it live:&lt;/strong&gt; &lt;a href="https://ej2.syncfusion.com/javascript/demos/#/bootstrap5/pdfviewer/default.html" rel="noopener noreferrer"&gt; JavaScript PDF Viewer Demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re a Syncfusion user, you can download the setup from the &lt;a href="https://www.syncfusion.com/account/login" rel="noopener noreferrer"&gt;license and downloads&lt;/a&gt; page. Otherwise, you can download a free &lt;a href="https://www.syncfusion.com/downloads" rel="noopener noreferrer"&gt;30-day trial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also contact us through our &lt;a href="https://www.syncfusion.com/forums" rel="noopener noreferrer"&gt;support forum&lt;/a&gt;, &lt;a href="https://support.syncfusion.com/" rel="noopener noreferrer"&gt;support portal&lt;/a&gt;, or &lt;a href="https://www.syncfusion.com/feedback/maui" rel="noopener noreferrer"&gt;feedback portal&lt;/a&gt; for queries. We are always happy to assist you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Blogs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/fillable-pdf-forms-in-javascript" rel="noopener noreferrer"&gt;https://www.syncfusion.com/blogs/post/fillable-pdf-forms-in-javascript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/javascript-pdf-signature" rel="noopener noreferrer"&gt;How to Add and Customize Signature Blocks in PDFs Using JavaScript PDF Viewer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/create-fillable-pdf-forms-javascript" rel="noopener noreferrer"&gt;How to Create Interactive Fillable PDF Forms Using JavaScript PDF Viewer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/memory-leaks-in-javascript-pdf-viewer" rel="noopener noreferrer"&gt;How to Fix Memory Leaks in JavaScript PDF Viewers: Best Practices and Debugging Tips&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally published at &lt;a href="//This%20article%20was%20originally%20published%20at%20Syncfusion.com."&gt;Syncfusion.com.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>pdf</category>
      <category>documenteditor</category>
      <category>documentprocessing</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to Secure Multi-User PDF Signing in a React PDF Viewer</title>
      <dc:creator>Phinter Atieno</dc:creator>
      <pubDate>Wed, 04 Feb 2026 17:12:56 +0000</pubDate>
      <link>https://forem.com/syncfusion/how-to-secure-multi-user-pdf-signing-in-a-react-pdf-viewer-2n75</link>
      <guid>https://forem.com/syncfusion/how-to-secure-multi-user-pdf-signing-in-a-react-pdf-viewer-2n75</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Struggling to build a secure multi‑party document‑signing workflow? You can enable user‑based e‑signatures in a React PDF Viewer by authenticating recipients, assigning signature fields, validating roles, and locking down PDF workflows to create a compliance‑ready signing experience.&lt;/p&gt;

&lt;p&gt;Building a reliable e‑signature workflow is rarely straightforward. In today’s remote‑first environment, businesses expect fast, secure, and legally compliant signing tools that eliminate printing and manual processes. Developers, however, face challenges, especially when supporting multiple signers, enforcing signing order, validating fields, and securing completed documents.&lt;/p&gt;

&lt;p&gt;This guide walks you through implementing a structured, recipient‑aware e‑signature workflow using &lt;a href="https://www.syncfusion.com/react-ui-components/react-pdf-viewer" rel="noopener noreferrer"&gt;Syncfusion&lt;sup&gt;®&lt;/sup&gt; React PDF Viewer&lt;/a&gt;. Throughout this tutorial, you’ll learn how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authenticate recipients before enabling signing.&lt;/li&gt;
&lt;li&gt;Assign signature fields dynamically with clear visual cues.&lt;/li&gt;
&lt;li&gt;Validate user inputs in real time for accuracy and compliance.&lt;/li&gt;
&lt;li&gt;Finalize and lock documents securely through field flattening.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end, you’ll have an interactive signing workflow that transforms static PDFs into smart, dynamic documents suitable for modern digital processes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a React project with Syncfusion PDF Viewer
&lt;/h2&gt;

&lt;p&gt;Before you can build the signing workflow, you’ll need to set up your React environment and configure the &lt;strong&gt;Syncfusion PDF Viewer&lt;/strong&gt;. The steps below guide you through initializing your project, installing dependencies, importing styles, and enabling the Form Designer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Initialize your React project
&lt;/h3&gt;

&lt;p&gt;Start by creating a new React application using &lt;strong&gt;Create React App&lt;/strong&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app esigningagreement
&lt;span class="nb"&gt;cd &lt;/span&gt;esigningagreement
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This scaffolds a clean React workspace to host your PDF signing workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Install Syncfusion React PDF Viewer
&lt;/h3&gt;

&lt;p&gt;Next, install the required Syncfusion React PDF Viewer package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @syncfusion/ej2-react-pdfviewer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This package provides the components and APIs needed to load, edit, and design interactive PDFs in React.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Import required styles
&lt;/h3&gt;

&lt;p&gt;To ensure consistent styling across viewer components, import the required CSS files into &lt;strong&gt;index.css:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../node_modules/@syncfusion/ej2-base/styles/material.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../node_modules/@syncfusion/ej2-buttons/styles/material.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../node_modules/@syncfusion/ej2-dropdowns/styles/material.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../node_modules/@syncfusion/ej2-inputs/styles/material.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../node_modules/@syncfusion/ej2-navigations/styles/material.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../node_modules/@syncfusion/ej2-popups/styles/material.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../node_modules/@syncfusion/ej2-splitbuttons/styles/material.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../node_modules/@syncfusion/ej2-pdfviewer/styles/material.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These style sheets ensure that every toolbar element, dialog, and form field renders with the correct theme and layout.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Load and configure the PDF Viewer with form designer
&lt;/h3&gt;

&lt;p&gt;With the setup complete and the PDF Viewer installed, you’re ready to load a PDF document and enable the &lt;strong&gt;Form Designer&lt;/strong&gt; tools. These tools allow you to create and edit interactive form fields directly within the viewer, making them ideal for building secure and flexible e‑signature workflows.&lt;/p&gt;

&lt;p&gt;To proceed, navigate to the &lt;strong&gt;&lt;code&gt;index.tsx&lt;/code&gt;&lt;/strong&gt; TypeScript file and add the following code to load the document and configure the PDF Viewer with form designer capabilities.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* PDF Viewer with form designer and other tools enabled */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PdfViewerComponent&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pdfViewer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pdfViewer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;resourceUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.syncfusion.com/ej2/31.2.10/dist/ej2-pdfviewer-lib&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;calc(100vh - 70px)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="nx"&gt;enableToolbar&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;documentPath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/assets/SoftwareLicenseAgreement.pdf&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;formFieldAdd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formFieldAdd&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;isFormDesignerToolbarVisible&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;documentLoad&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;documentLoaded&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;showNotificationDialog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;formFieldPropertiesChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fieldChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;enableDownload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Inject required PDF viewer services and features */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Inject&lt;/span&gt; &lt;span class="nx"&gt;services&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;
                    &lt;span class="nx"&gt;Toolbar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Magnification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Navigation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Annotation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LinkAnnotation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BookmarkView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ThumbnailView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TextSelection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TextSearch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FormFields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FormDesigner&lt;/span&gt;
    &lt;span class="p"&gt;]}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/PdfViewerComponent&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FCreating-and-editing-interactive-form-fields-inside-the-React-PDF-Viewer-1024x441.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FCreating-and-editing-interactive-form-fields-inside-the-React-PDF-Viewer-1024x441.png" alt="Creating and editing interactive form fields inside the React PDF Viewer" width="800" height="344"&gt;&lt;/a&gt;&lt;br&gt;Creating and editing interactive form fields inside the React PDF Viewer
  &lt;/p&gt;

&lt;p&gt;This configuration enables the Form Designer toolbar and supporting services, allowing you to create, assign, and manage interactive form fields directly inside the &lt;a href="https://help.syncfusion.com/document-processing/pdf/pdf-viewer/react/getting-started" rel="noopener noreferrer"&gt;React PDF Viewer&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recipient authentication: The first step to secure the signing flow
&lt;/h2&gt;

&lt;p&gt;Before you design or assign any form fields, you need to ensure that only authorized recipients can sign the document. This is where the &lt;strong&gt;Recipient Authentication Setup&lt;/strong&gt; page becomes essential. It forms the foundation of a secure, user‑based e‑signature workflow by allowing you to define, manage, and validate every signer before moving into document preparation.&lt;/p&gt;

&lt;p&gt;Getting this step right prevents misassigned fields, accidental signer mix-ups, and workflow disruptions, creating a smoother experience for both developers and recipients.&lt;/p&gt;

&lt;p&gt;Let’s walk through the setup:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create a recipient form
&lt;/h3&gt;

&lt;p&gt;Begin by creating a new &lt;strong&gt;TypeScript JSX&lt;/strong&gt; file named &lt;code&gt;RecipientSetup.tsx&lt;/code&gt;. This component enables users to &lt;strong&gt;add&lt;/strong&gt;, &lt;strong&gt;edit&lt;/strong&gt;, and &lt;strong&gt;remove&lt;/strong&gt; recipients before the PDF Viewer is loaded.&lt;/p&gt;

&lt;p&gt;The form collects essential signer information such as &lt;strong&gt;Name&lt;/strong&gt; and &lt;strong&gt;Email&lt;/strong&gt;, and uses modern UI components to keep the interface clean and intuitive. The page starts with one recipient by default, and the &lt;strong&gt;+ Add Recipient&lt;/strong&gt; button lets users dynamically add more, making it flexible enough for everything from simple two‑party signatures to complex, multi‑signer agreements.&lt;/p&gt;

&lt;p&gt;Once recipients are confirmed, users can move on to adding handwritten signatures and mapping fields to the proper signers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Form for entering recipient details */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userForm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formRef&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formSubmit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;recipients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
            &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
                &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;40px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
            &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
                &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
                    &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;30px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;alignItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;80%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Recipient Name Field */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;
                        &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
                            &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;5px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="na"&gt;fontWeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="nx"&gt;Recipient&lt;/span&gt; &lt;span class="nx"&gt;Name&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TextBoxComponent&lt;/span&gt;
                        &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Enter recipient name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                        &lt;span class="nx"&gt;floatLabelType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                        &lt;span class="nx"&gt;cssClass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;e-outline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                        &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                        &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`name_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                        &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;recipientChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;userName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Recipient Email Field */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;
                        &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
                            &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;5px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="na"&gt;fontWeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="nx"&gt;Recipient&lt;/span&gt; &lt;span class="nx"&gt;Email&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TextBoxComponent&lt;/span&gt;
                        &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Enter recipient email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                        &lt;span class="nx"&gt;floatLabelType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                        &lt;span class="nx"&gt;cssClass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;e-outline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                        &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userEmail&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                        &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`email_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                        &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;recipientChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;userEmail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Remove recipient button */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ButtonComponent&lt;/span&gt;
                    &lt;span class="nx"&gt;cssClass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;e-flat e-danger&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                    &lt;span class="nx"&gt;iconCss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;e-icons e-trash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                    &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;22px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;40px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;40px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
                    &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;removeRecipient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;))}&lt;/span&gt;

    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Submit button */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
        &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
            &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;40px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ButtonComponent&lt;/span&gt;
            &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formBtnRef&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;isPrimary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;cssClass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;e-success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;40%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;40px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nx"&gt;Continue&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt; &lt;span class="nx"&gt;Creation&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ButtonComponent&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step: 2 Real-time input validation
&lt;/h3&gt;

&lt;p&gt;Accurate signer information is essential for a secure workflow. Missing names, invalid emails, or malformed inputs can break the signing process later. Using FormValidator, you can validate fields dynamically as recipients are added or removed.&lt;/p&gt;

&lt;p&gt;Validation enforces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Required fields for both &lt;strong&gt;name&lt;/strong&gt; and &lt;strong&gt;email&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A minimum name length for clarity and professionalism.&lt;/li&gt;
&lt;li&gt;A valid email format to prevent delivery issues and maintain trust.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best part? Validation rules automatically update whenever the recipient list changes, ensuring a seamless user experience.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;dynamicRules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

            &lt;span class="nx"&gt;recipients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;dynamicRules&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`name_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;* Name is required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="na"&gt;minLength&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;* Name must be at least 3 characters&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;};&lt;/span&gt;
                &lt;span class="nx"&gt;dynamicRules&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`email_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;* Email is required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;* Please enter a valid email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;};&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;

            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;validatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

                &lt;span class="c1"&gt;// Update existing validator rules without destroying them&lt;/span&gt;
                &lt;span class="nx"&gt;validatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dynamicRules&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

                &lt;span class="c1"&gt;// Create new validator only if it doesn't exist&lt;/span&gt;
                &lt;span class="nx"&gt;validatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormValidator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dynamicRules&lt;/span&gt;
                &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;recipients&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Navigation and data persistence
&lt;/h3&gt;

&lt;p&gt;Once all inputs pass validation, the recipient list is stored safely in &lt;strong&gt;localStorage&lt;/strong&gt;. This allows the PDF Viewer to access signer information when generating and assigning form fields.&lt;/p&gt;

&lt;p&gt;After the details are saved, the user can click &lt;strong&gt;Continue to Form Creation&lt;/strong&gt; to move directly into the PDF Viewer interface, where the interactive document design begins.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Handles form submission, validates input, stores data, and navigates to the PDF viewer&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FormEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;       
        &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;validatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;validatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validRecipients&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;recipients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userEmail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recipients&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;validRecipients&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/pdf-viewer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FForm-creation-in-React-PDF-Viewer-1-1024x642.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FForm-creation-in-React-PDF-Viewer-1-1024x642.png" alt="Form creation in React PDF Viewer" width="800" height="501"&gt;&lt;/a&gt;&lt;br&gt;Form creation in React PDF Viewer
  &lt;/p&gt;

&lt;h2&gt;
  
  
  Interactive PDF designer: Add and assign signature fields easily
&lt;/h2&gt;

&lt;p&gt;With authentication complete, the next step is converting a static PDF into a structured, signable form where multiple recipients can fill and sign fields in the correct order.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Import recipients from local storage
&lt;/h3&gt;

&lt;p&gt;Begin by loading the recipient information saved during the authentication step. Retrieve the stored data from &lt;code&gt;localStorage&lt;/code&gt;, convert it into the internal &lt;strong&gt;UserDetails&lt;/strong&gt; structure, and merge it with any existing user list, automatically filtering out duplicates.&lt;/p&gt;

&lt;p&gt;This step ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A secure, structured workflow for multi‑party agreements.&lt;/li&gt;
&lt;li&gt;Accurate, recipient‑specific field assignment (especially for signatures).&lt;/li&gt;
&lt;li&gt;Reliable mapping between each signer and their form fields.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the data is loaded, you can use the &lt;strong&gt;Form Designer Toolbar&lt;/strong&gt; to add fields such as &lt;strong&gt;Signature&lt;/strong&gt;, &lt;strong&gt;Initials&lt;/strong&gt;, or &lt;strong&gt;Text&lt;/strong&gt;, and assign each field to the correct recipient.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Load recipients from localStorage, convert them to userDetails format, and merge without duplicates&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;storedRecipients&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recipients&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fieldId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;newUsers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserDetails&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storedRecipients&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;recipients&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storedRecipients&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;recipients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;newUsers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;Mail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userEmail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;fieldIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fieldId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;fieldId&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;setUserDetails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;existingEmails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Mail&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredNewUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newUsers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;existingEmails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Mail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;filteredNewUsers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error parsing user info or recipients:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;span class="s2"&gt;``&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Map fields to recipients
&lt;/h3&gt;

&lt;p&gt;After loading recipients, the next step is assigning each form field to the correct signer. Whether it’s a signature box, initials, or a text input, proper field mapping is essential for a secure and organized signing experience.&lt;/p&gt;

&lt;p&gt;This step provides important benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear and accurate field ownership for each participant.&lt;/li&gt;
&lt;li&gt;Protection of sensitive data through controlled field access.&lt;/li&gt;
&lt;li&gt;Prevention of unauthorized edits, ensuring workflow integrity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Correctly mapped fields mean each signer interacts only with their assigned inputs, maintaining clarity, compliance, and trust throughout the signing process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Renders the dialog content with user selection and submit button&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getRecipientDialogContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dialog-content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;fontWeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bold&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;16px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nx"&gt;Select&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="na"&gt;User&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;radio-options&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;50px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;30px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;radio-item&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RadioButtonComponent&lt;/span&gt;
                            &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;radioBtnRef&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                            &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                            &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userType&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                            &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                            &lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selectedUser&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                            &lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="p"&gt;))}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button-container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;25px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;textAlign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ButtonComponent&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;e-btn e-primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;80%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;5px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userSelectionSubmit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Submit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ButtonComponent&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your dialog for selecting a recipient looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FMapping-fields-to-recipients-1024x483.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FMapping-fields-to-recipients-1024x483.png" alt="Mapping fields to recipients" width="800" height="377"&gt;&lt;/a&gt;&lt;br&gt;Mapping fields to recipients
  &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Enhance field visibility for recipients
&lt;/h3&gt;

&lt;p&gt;To make the signing experience intuitive, especially in multi‑signer workflows, style each assigned field using a unique &lt;strong&gt;background color&lt;/strong&gt;. This is done via the &lt;strong&gt;&lt;code&gt;customData&lt;/code&gt;&lt;/strong&gt; property and provides immediate visual clarity for each signer.&lt;/p&gt;

&lt;p&gt;This enhancement offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A clearly guided signing process.&lt;/li&gt;
&lt;li&gt;Reduced confusion when multiple recipients are involved.&lt;/li&gt;
&lt;li&gt;Strong linkage between recipients and their assigned fields.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By applying distinct colors, signers can easily identify the fields they need to complete, keeping the workflow organized and user‑friendly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Handles the Submit button click after user selection&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userSelectionSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setSelectedUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;radioBtnRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;getSelectedValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;setStatus&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;hideDialog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nf"&gt;dialogClose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Get the last added form field&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formFields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pdfViewer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;retrieveFormFields&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formFields&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="nx"&gt;formFields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// Find the selected user's details&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;selectedUser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastField&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userColors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Mail&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getRandomLightColor&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nf"&gt;setUserColors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Mail&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Check if the field is a signature field (adjust property as needed)&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isSignatureField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lastField&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SignatureField&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;lastField&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sign&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Use 40% opacity for signature fields, solid for others&lt;/span&gt;
        &lt;span class="nx"&gt;userColour&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isSignatureField&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;hexToRgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nx"&gt;pdfViewer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;formDesigner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateFormField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nx"&gt;lastField&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;customData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Mail&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lastField&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userColour&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;isRequired&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;borderColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#303030&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FEnhancing-field-visibility-using-the-customData-property-1-1024x485.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FEnhancing-field-visibility-using-the-customData-property-1-1024x485.png" alt="Enhancing field visibility using the customData property" width="800" height="378"&gt;&lt;/a&gt;&lt;br&gt;Enhancing field visibility using the customData property
  &lt;/p&gt;

&lt;p&gt;When the &lt;strong&gt;Form Designer Toolbar&lt;/strong&gt; is open, the viewer is in design mode, allowing you to place and configure fields. Closing the toolbar switches the viewer back into interactive mode, where recipients can begin filling and signing their assigned fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enforce signing order and validation
&lt;/h2&gt;

&lt;p&gt;To maintain a structured, compliant, and error‑free signing experience, it’s important to enforce the correct signing order and validate all required fields before allowing recipients to proceed. This ensures no signer is skipped and helps preserve the integrity of the document throughout the workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step:1 Validate signing context
&lt;/h3&gt;

&lt;p&gt;When the Form Designer toolbar is closed, the PDF Viewer automatically switches to interactive mode. At this point, the application should determine which signer is active and display &lt;strong&gt;only the fields assigned to that recipient&lt;/strong&gt;. This keeps the interface clean and prevents users from interacting with fields that don’t belong to them.&lt;/p&gt;

&lt;p&gt;This approach ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each signer sees only their assigned fields.&lt;/li&gt;
&lt;li&gt;The signing flow remains intuitive and distraction‑free.&lt;/li&gt;
&lt;li&gt;Errors are minimized in multi‑recipient workflows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By validating context and controlling visibility, you maintain a secure and compliant e‑signature flow from signer to signer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Initializes event listener for closing the form designer and shows the user dropdown&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;documentLoaded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pdfViewer_formdesigner_closeContainer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setShowDropdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pdfViewer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nx"&gt;pdfViewer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;designerMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nf"&gt;showOnlyCurrentUserFields&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step:2 Enforce sequential signing
&lt;/h3&gt;

&lt;p&gt;Next, enforce a strict signing order, ensuring each recipient completes their required fields before the workflow advances.&lt;/p&gt;

&lt;p&gt;When transitioning to the next signer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validate all required fields assigned to the current signer.&lt;/li&gt;
&lt;li&gt;Prevent progression if any mandatory fields are incomplete.&lt;/li&gt;
&lt;li&gt;Display a helpful message prompting the signer to fill missing inputs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This prevents incomplete signatures, maintains document consistency, and guarantees a reliable, structured signing experience, especially important when adding legally binding e‑signatures to PDFs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FEnforcing-sequential-signing-using-the-React-PDF-Viewer-2-1024x485.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FEnforcing-sequential-signing-using-the-React-PDF-Viewer-2-1024x485.png" alt="Enforcing sequential signing using the React PDF Viewer" width="800" height="378"&gt;&lt;/a&gt;&lt;br&gt;Enforcing sequential signing using the React PDF Viewer
  &lt;/p&gt;

&lt;h2&gt;
  
  
  Finalizing the document
&lt;/h2&gt;

&lt;p&gt;Once all recipients have completed their assigned fields, the document must be finalized securely. Finalization includes enabling the finishing action and converting the signed PDF into a non‑editable file.&lt;/p&gt;

&lt;p&gt;This phase involves two key steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step:1 Activate the finish signing button
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Finish Signing&lt;/strong&gt; button stays disabled until all mandatory fields are completed. By tracking field changes through the &lt;code&gt;formFieldPropertiesChange&lt;/code&gt; event, the app can automatically detect when the signer has fulfilled all requirements.&lt;/p&gt;

&lt;p&gt;After validation succeeds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable the &lt;strong&gt;Finish Signing&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;&lt;code&gt;enableDownload&lt;/code&gt;&lt;/strong&gt; to true so users can download or submit the completed document.&lt;/li&gt;
&lt;li&gt;Optionally allow the signer to add a handwritten signature for a more authentic experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FActivating-the-finish-signing-button-in-the-React-PDF-Viewer-1-1024x484.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FActivating-the-finish-signing-button-in-the-React-PDF-Viewer-1-1024x484.png" alt="Activating the finish signing button in the React PDF Viewer" width="800" height="378"&gt;&lt;/a&gt;&lt;br&gt;Activating the finish signing button in the React PDF Viewer
  &lt;/p&gt;

&lt;h3&gt;
  
  
  Step:2 Secure the document
&lt;/h3&gt;

&lt;p&gt;The final step is to &lt;strong&gt;flatten&lt;/strong&gt; all form fields. Flattening converts interactive elements into static content, making the PDF non‑editable and tamper‑proof.&lt;/p&gt;

&lt;p&gt;This is essential because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It prevents further modification of completed signatures.&lt;/li&gt;
&lt;li&gt;Ensures document integrity.&lt;/li&gt;
&lt;li&gt;Meets legal and compliance standards for digital signing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code below handles saving, flattening, downloading, and securing the viewer UI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Handles the final signing process; saves the PDF, sends it to the server, downloads the signed version, and disables UI controls&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;finishSigning&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// Show the spinner when signing starts&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spinnerTarget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spinnerTarget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;showSpinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spinnerTarget&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://document.syncfusion.com/web-services/pdf-viewer/api/pdfviewer/FlattenDownload&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;pdfViewer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;saveAsBlob&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;convertBlobToBase64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;base64String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;httpResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;XMLHttpRequest&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nx"&gt;httpResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;httpResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRequestHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json; charset=UTF-8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;base64String&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="nx"&gt;httpResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

                &lt;span class="c1"&gt;// Always hide spinner at the end (success or error)&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spinnerTarget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;hideSpinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spinnerTarget&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;httpResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;responseBase64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;httpResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;responseText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
                    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responseBase64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createBlobFromBase64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responseBase64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blobUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="nf"&gt;downloadDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blobUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="nx"&gt;pdfViewer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;httpResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;responseText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;btnElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="nx"&gt;btnElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userMenu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="nx"&gt;userMenu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid base64 response.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Download failed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
            &lt;span class="nx"&gt;httpResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spinnerTarget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;hideSpinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spinnerTarget&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;An error occurred during the download:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
            &lt;span class="nx"&gt;httpResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spinnerTarget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;hideSpinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spinnerTarget&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error saving Blob:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FFlattening-the-form-fields-using-the-React-PDF-Viewer-1024x489.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F01%2FFlattening-the-form-fields-using-the-React-PDF-Viewer-1024x489.png" alt="Flattening the form fields using the React PDF Viewer" width="800" height="382"&gt;&lt;/a&gt;&lt;br&gt;Flattening the form fields using the React PDF Viewer
  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Refer to the official &lt;a href="https://help.syncfusion.com/document-processing/pdf/pdf-library/net/working-with-forms#flattening-form-fields-in-a-pdf" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; for more on flattening form fields to prevent edits and ensure signature security.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub reference
&lt;/h2&gt;

&lt;p&gt;To explore the full implementation, you can access the complete project in the &lt;a href="https://github.com/SyncfusionExamples/react-pdf-viewer-examples/tree/master/How%20to/Create%20Signable%20PDF%20Forms%20with%20Dynamic%20User" rel="noopener noreferrer"&gt;GitHub demo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thanks for reading! In this guide, you learned that creating a secure and intuitive digital signing experience goes beyond simply adding signature fields. It requires designing a &lt;strong&gt;structured, user-aware workflow&lt;/strong&gt; that enforces signing order, validates input, and ensures compliance, all while keeping the process smooth and user-friendly.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://www.syncfusion.com/react-ui-components/react-pdf-viewer" rel="noopener noreferrer"&gt;Syncfusion’s React PDF Viewer&lt;/a&gt;, developers gain full control over every stage of the user-based e-signature process. By leveraging advanced features like dynamic field assignment, real-time validation, conditional UI behavior, and secure document finalization. This approach strengthens security and integrates seamlessly into modern React applications, making digital signing workflows efficient and reliable.&lt;/p&gt;

&lt;p&gt;Dive deeper with the React PDF Viewer User &lt;a href="https://help.syncfusion.com/document-processing/pdf/pdf-viewer/react/getting-started" rel="noopener noreferrer"&gt;guide&lt;/a&gt; or try it live in the React PDF Viewer &lt;a href="https://www.syncfusion.com/account/downloads#/tailwind3/pdfviewer/default" rel="noopener noreferrer"&gt;demo&lt;/a&gt;. If you’re a Syncfusion user, you can download the setup from the &lt;a href="https://www.syncfusion.com/account/downloads" rel="noopener noreferrer"&gt;license and downloads&lt;/a&gt; page. Otherwise, you can download a free &lt;a href="https://www.syncfusion.com/downloads/" rel="noopener noreferrer"&gt;30-day trial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also contact us through our &lt;a href="https://www.syncfusion.com/forums" rel="noopener noreferrer"&gt;support forum&lt;/a&gt;, &lt;a href="https://support.syncfusion.com/" rel="noopener noreferrer"&gt;support portal&lt;/a&gt;, or &lt;a href="https://www.syncfusion.com/feedback" rel="noopener noreferrer"&gt;feedback portal&lt;/a&gt; for queries. We are always happy to assist you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Blogs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/editable-pdfs-in-react" rel="noopener noreferrer"&gt;How to Embed and Edit PDFs in React Using the React PDF Viewer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/pdf-annotations-in-react" rel="noopener noreferrer"&gt;How to Implement PDF Annotations in React for Seamless Document Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/role-based-pdf-annotation-in-react" rel="noopener noreferrer"&gt;Secure Role-Based PDF Annotation in React: Filter, Lock, and Collaborate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/organize-pdf-pages-react" rel="noopener noreferrer"&gt;How To Organize PDF Pages in React for Seamless Document Workflows&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally published at &lt;a href="https://www.syncfusion.com/blogs/post/user-based-e-signature-react-pdf-viewer?preview_id=221483&amp;amp;preview_nonce=8d30a30740&amp;amp;preview=true&amp;amp;_thumbnail_id=223351" rel="noopener noreferrer"&gt;Syncfusion.com.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>pdf</category>
      <category>documentmanagement</category>
      <category>pdfviewer</category>
      <category>react</category>
    </item>
    <item>
      <title>Essential Studio Support SLA Updates: Response Times, Tiers, and Escalations</title>
      <dc:creator>Phinter Atieno</dc:creator>
      <pubDate>Tue, 03 Feb 2026 15:37:55 +0000</pubDate>
      <link>https://forem.com/syncfusion/essential-studio-support-sla-updates-response-times-tiers-and-escalations-4nh2</link>
      <guid>https://forem.com/syncfusion/essential-studio-support-sla-updates-response-times-tiers-and-escalations-4nh2</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Explore the key changes to the support SLA, featuring updated tier definitions, clarified response benchmarks, structured priority workflows, detailed escalation routes, defined support hours, and revised hotfix policies.&lt;/p&gt;

&lt;p&gt;We’ve rolled out an updated Support and Product Maintenance Service Level Agreement (&lt;strong&gt;SLA&lt;/strong&gt;) for Essential Studio as part of Version &lt;strong&gt;32.1.24&lt;/strong&gt;, effective &lt;strong&gt;January 20&lt;/strong&gt;, &lt;strong&gt;2026&lt;/strong&gt;. This update brings clearer expectations, more structured support tiers, and predictable response guidelines to help developers plan and troubleshoot with confidence.&lt;/p&gt;

&lt;p&gt;Our goal is to make every support interaction more transparent and easier to navigate from the moment you submit a ticket to the final resolution. If you want to review the full SLA, you can find it here: Syncfusion&lt;sup&gt;®&lt;/sup&gt; &lt;a href="https://s3.amazonaws.com/files2.syncfusion.com/web/support/sla/32.1/syncfusion_software_support_sla.pdf" rel="noopener noreferrer"&gt;Software Support SLA&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this article, you’ll get a concise look at what’s changed and why these updates matter for your development workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s new in the updated SLA
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Clearer support tiers for different needs
&lt;/h3&gt;

&lt;p&gt;The previous SLA offered only two tiers, Standard Support ( &lt;strong&gt;Base SDK&lt;/strong&gt; ) and Enterprise Support (Premium), which didn’t fully align with the range of developer workflows. The updated SLA now introduces three well-defined support tiers, giving teams more flexibility and clearer expectations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Standard support&lt;/strong&gt;: Response guaranteed in 2 business days.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business support&lt;/strong&gt;: Response guaranteed in 1 business day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise support&lt;/strong&gt;: Response guaranteed in 8 business hours.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This structure helps teams choose a level that fits their release schedules and operational demands. If you’re unsure which tier applies to your subscription, you can reach out to Client Services for clarification.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. A consistent, priority-based approach to incident handling
&lt;/h3&gt;

&lt;p&gt;The updated SLA formalizes how &lt;strong&gt;P1 (critical)&lt;/strong&gt;, &lt;strong&gt;P2 (high impact)&lt;/strong&gt;, and &lt;strong&gt;P3 (standard)&lt;/strong&gt; incidents are handled across all tiers. For each priority level, the SLA defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expected initial response times.&lt;/li&gt;
&lt;li&gt;How often do you receive status updates.&lt;/li&gt;
&lt;li&gt;Target timeframes for resolution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your submitted priority is considered, but the Syncfusion support team assigns the final classification to maintain consistency and fairness across all requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Feature requests are now clearly outside SLA scope
&lt;/h3&gt;

&lt;p&gt;To eliminate confusion, the SLA now states that feature requests, enhancements, and new functionality are outside the scope of support commitments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SLA performance metrics apply only to&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Troubleshooting&lt;/li&gt;
&lt;li&gt;Defect investigation&lt;/li&gt;
&lt;li&gt;Fixes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feature ideas continue through the product planning and roadmap process instead of the support SLA.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional clarifications in the updated SLA
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Clear definitions for key support terms
&lt;/h3&gt;

&lt;p&gt;The SLA now defines essential terminology so teams know exactly how timelines work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Response time&lt;/strong&gt;: When a qualified support engineer delivers the first meaningful reply after a ticket is received.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resolution time&lt;/strong&gt;: When a workaround, permanent fix, or agreed-upon remediation plan is provided.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These definitions remove guesswork and help developers set more realistic expectations during active debugging.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tier-specific services and escalation paths
&lt;/h3&gt;

&lt;p&gt;The SLA also details support variations across the three tiers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Support hours&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standard and Business Support operate during regular business hours (Monday–Friday).&lt;/li&gt;
&lt;li&gt;Enterprise Support includes 24×7 coverage for P1 incidents.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Escalation paths&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Business Support includes access to senior engineers for escalations.&lt;/li&gt;
&lt;li&gt;Enterprise Support includes a dedicated escalation path and named contact.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hotfix delivery&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standard Support does not guarantee hotfixes.&lt;/li&gt;
&lt;li&gt;Business Support may offer patches or workarounds depending on the situation.&lt;/li&gt;
&lt;li&gt;Enterprise Support can receive hotfixes outside the normal release cycle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These distinctions help teams understand what level of assistance and remediation they can expect based on their support tier.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to get the most from the updated SLA
&lt;/h2&gt;

&lt;p&gt;You can help the support team move faster and deliver accurate answers by sharing the right details upfront. To get the most value from the updated SLA, make sure you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Review the full SLA for &lt;strong&gt;Version 32.1.24&lt;/strong&gt; to understand all tiers and commitments.&lt;/li&gt;
&lt;li&gt;Reach out to Client Services if you’re unsure which support tier your subscription includes.&lt;/li&gt;
&lt;li&gt;Provide essential information with every ticket, including:

&lt;ul&gt;
&lt;li&gt;Clear reproduction steps&lt;/li&gt;
&lt;li&gt;Relevant logs&lt;/li&gt;
&lt;li&gt;Diagnostic data&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Supplying this information early speeds up the investigation process and helps the team meet response and resolution targets more consistently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Which support level am I on, and what response time applies to me?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Standard Support:&lt;/strong&gt; 2 business days&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business Support:&lt;/strong&gt; 1 business day&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise Support:&lt;/strong&gt; 8 business hours
If you're unsure which level applies to your subcsription, contact &lt;a href="https://www.syncfusion.com/company/contact-us" rel="noopener noreferrer"&gt;Syncfusion Client Services&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Can I choose the priority (P1/P2/P3) when I raise a ticket?&lt;/strong&gt;&lt;br&gt;
You can submit a priority when raising the request, and the final prioprity level is determined by Syncfusion Support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are feature requests included in SLA commitments?&lt;/strong&gt;&lt;br&gt;
No. Feature requests, product enhancements, and requests for new functionality are excluded from SLA coverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thank you for reading!. The updated SLA introduces meaningful improvements, bringing greater clarity and structure to your support experience. Here’s a quick recap of what changed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Three support tiers are now available: Standard, Business, and Enterprise.&lt;/li&gt;
&lt;li&gt;A unified priority-based workflow defining response, update, and resolution timelines.&lt;/li&gt;
&lt;li&gt;Feature requests are clearly excluded from SLA commitments.&lt;/li&gt;
&lt;li&gt;Standardized definitions for response time and resolution time.&lt;/li&gt;
&lt;li&gt;Tier-specific clarity around support hours, escalation paths, and hotfix availability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have any questions about how these updates relate to your current subscription or ongoing development work, &lt;a href="https://www.syncfusion.com/company/contact-us" rel="noopener noreferrer"&gt;our team is available to assist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We appreciate your continued trust in Syncfusion and look forward to supporting your projects with consistency, transparency, and professionalism.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Blogs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/pdf-viewer-docx-editor-2025-vol4" rel="noopener noreferrer"&gt;Essential Studio 2025 Volume 4: What’s New in PDF Viewer and DOCX Editor SDKs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/whats-new-document-sdk-2025-volume-4" rel="noopener noreferrer"&gt;Essential Studio 2025 Volume 4: What’s New in PDF, Word, Excel &amp;amp; PowerPoint Libraries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/essential-studio-2025-volume-4" rel="noopener noreferrer"&gt;Syncfusion Essential Studio 2025 Volume 4: Key Updates for Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/javascript-ui-components-2025-vol-3" rel="noopener noreferrer"&gt;Essential Studio 2025 Volume 3: Latest UI Updates for React, Angular &amp;amp; JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally published at &lt;a href="https://www.syncfusion.com/blogs/post/essential-studio-support-sla-update" rel="noopener noreferrer"&gt;Syncfusion.com.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>slaupdate</category>
      <category>developerplatforms</category>
      <category>incidentpriority</category>
      <category>productmaintenance</category>
    </item>
    <item>
      <title>How to Add Stamps to PDFs Using C# for Faster Reviews</title>
      <dc:creator>Phinter Atieno</dc:creator>
      <pubDate>Tue, 03 Feb 2026 15:37:45 +0000</pubDate>
      <link>https://forem.com/syncfusion/how-to-add-stamps-to-pdfs-using-c-for-faster-reviews-43fe</link>
      <guid>https://forem.com/syncfusion/how-to-add-stamps-to-pdfs-using-c-for-faster-reviews-43fe</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Learn how to add stamps to PDFs using C# in three practical methods with the .NET PDF Library. Add approval stamps, logos, or custom text, and see how to flatten or remove stamps to streamline workflows, improve compliance, and enhance document branding.&lt;/p&gt;

&lt;p&gt;Stamps in PDF documents are more than simple visual markers; they’re essential tools for approval processes, branding, and workflow automation. Whether you need to mark a file as &lt;strong&gt;Approved&lt;/strong&gt;, apply a company logo, or insert custom metadata, stamps help clearly communicate status and ownership.&lt;/p&gt;

&lt;p&gt;In this guide, you’ll explore three practical ways for stamping PDF files using C#. With the &lt;a href="https://www.syncfusion.com/document-sdk/net-pdf-library" rel="noopener noreferrer"&gt;Syncfusion&lt;sup&gt;®&lt;/sup&gt; .NET PDF library&lt;/a&gt;, you can easily insert built-in icons, dynamic text, or images. You’ll also learn how to flatten or remove stamps, giving you complete control over document presentation and compliance.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a PDF stamp?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;PDF stamp&lt;/strong&gt; is a visual overlay placed on top of a PDF page to display status, branding, or metadata. Similar to a digital rubber stamp, it may include labels such as &lt;strong&gt;Approved&lt;/strong&gt;, &lt;strong&gt;Draft&lt;/strong&gt;, or &lt;strong&gt;time&lt;/strong&gt; / &lt;strong&gt;date&lt;/strong&gt; information. Stamps are stored as PDF annotations, which means they can be added, styled, removed, or flattened programmatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Difference between Stamp and Watermark
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;stamp&lt;/strong&gt; sits above the page content in the annotation layer and is commonly used for workflow indicators, approvals, or review actions.&lt;/p&gt;

&lt;p&gt;By contrast, a &lt;strong&gt;watermark&lt;/strong&gt; becomes part of the page’s main content layer. Watermarks are usually semi‑transparent and appear behind text or images. They’re typically used for branding, copyright, or subtle identifiers such as &lt;strong&gt;&lt;em&gt;Confidential&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add stamps to PDFs using C
&lt;/h2&gt;

&lt;p&gt;Before diving into examples, ensure your C# project references a PDF library that supports stamping. If starting fresh, create a .NET application and install the &lt;a href="https://www.nuget.org/packages/Syncfusion.Pdf.Net.Core" rel="noopener noreferrer"&gt;Syncfusion.PDF.NET.Core&lt;/a&gt; NuGet package as described in Syncfusion’s &lt;a href="https://help.syncfusion.com/document-processing/pdf/pdf-library/net/create-pdf-file-in-console" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Register your Syncfusion PDF Library license key at application startup to enable full functionality in production environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a stamp with a standard icon
&lt;/h2&gt;

&lt;p&gt;Syncfusion provides several built-in stamp appearances, such as &lt;strong&gt;Approved&lt;/strong&gt;, &lt;strong&gt;Draft&lt;/strong&gt;, and &lt;strong&gt;Confidential&lt;/strong&gt;. These pre-made icons save time because you can apply them directly without designing custom graphics. Just pick the icon that matches your workflow and apply it directly to the PDF.&lt;/p&gt;

&lt;p&gt;Here’s how you can do it in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Syncfusion.Drawing&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Syncfusion.Pdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Syncfusion.Pdf.Interactive&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Syncfusion.Pdf.Parsing&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Load the existing PDF document&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfLoadedDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfLoadedDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../../../../data/input.pdf"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Get the first page of the document&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfLoadedPage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// Create a rubber stamp annotation&lt;/span&gt;
    &lt;span class="n"&gt;PdfRubberStampAnnotation&lt;/span&gt; &lt;span class="n"&gt;rubberStamp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfRubberStampAnnotation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RectangleF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;390&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;480&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;163&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;49&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
        &lt;span class="s"&gt;"APPROVED"&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Set the standard stamp icon&lt;/span&gt;
    &lt;span class="n"&gt;rubberStamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Icon&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfRubberStampAnnotationIcon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Approved&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Enable appearance visibility across PDF viewers&lt;/span&gt;
    &lt;span class="n"&gt;rubberStamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetAppearance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Add annotation to the page&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Annotations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rubberStamp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Save the document&lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"stamp-pdf.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The image below shows how the stamp looks in the PDF.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FPDF-pages-with-stamp-annotations-1024x767.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FPDF-pages-with-stamp-annotations-1024x767.png" alt="PDF pages with stamp annotations" width="800" height="599"&gt;&lt;/a&gt;&lt;br&gt;PDF pages with stamp annotations
  &lt;/p&gt;

&lt;h2&gt;
  
  
  Creating stamps with dynamic content
&lt;/h2&gt;

&lt;p&gt;You can also insert dynamic data, such as decisions, usernames, and timestamps, to improve auditability, accountability, and compliance in document workflows.&lt;/p&gt;

&lt;p&gt;Below is the code you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Load the existing PDF document&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfLoadedDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfLoadedDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../../../../data/input.pdf"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Get the first page of the document&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfLoadedPage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// Create a rubberstamp annotation&lt;/span&gt;
    &lt;span class="n"&gt;PdfRubberStampAnnotation&lt;/span&gt; &lt;span class="n"&gt;rubberStamp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfRubberStampAnnotation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RectangleF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;390&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;480&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;163&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;49&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s"&gt;"dynamic-stamp"&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Draw the dynamic stamp content&lt;/span&gt;

    &lt;span class="c1"&gt;// Get the graphics of the stamp appearance&lt;/span&gt;
    &lt;span class="n"&gt;PdfGraphics&lt;/span&gt; &lt;span class="n"&gt;graphics&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rubberStamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Appearance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Normal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Graphics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Create background brush and border pen&lt;/span&gt;
    &lt;span class="n"&gt;PdfSolidBrush&lt;/span&gt; &lt;span class="n"&gt;backgroundBrush&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfSolidBrush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;229&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;239&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;224&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;PdfPen&lt;/span&gt; &lt;span class="n"&gt;borderPen&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfPen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;65&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;106&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="nf"&gt;DrawRoundedCornerRectangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RectangleF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;159&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;47&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;graphics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;backgroundBrush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;borderPen&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Create font for stamp text&lt;/span&gt;
    &lt;span class="n"&gt;PdfStandardFont&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfStandardFont&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfFontFamily&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Helvetica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Create font for date&lt;/span&gt;
    &lt;span class="n"&gt;PdfStandardFont&lt;/span&gt; &lt;span class="n"&gt;dateFont&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfStandardFont&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfFontFamily&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Helvetica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Create brush for text&lt;/span&gt;
    &lt;span class="n"&gt;PdfSolidBrush&lt;/span&gt; &lt;span class="n"&gt;textBrush&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfSolidBrush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;65&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;106&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// Draw the stamp text&lt;/span&gt;
    &lt;span class="n"&gt;graphics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DrawString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"APPROVED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;textBrush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PointF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// Draw the date text&lt;/span&gt;
    &lt;span class="n"&gt;graphics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DrawString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"on "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;dateFont&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;textBrush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PointF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;33&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// Add annotation to the page&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Annotations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rubberStamp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Save the document&lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dynamic-stamp-pdf.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also add the following code to draw a rounded-corner rectangle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Draw the rounded corner rectangle&lt;/span&gt;
&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DrawRoundedCornerRectangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;RectangleF&lt;/span&gt; &lt;span class="n"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;PdfGraphics&lt;/span&gt; &lt;span class="n"&gt;graphics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;cornerRadius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;PdfBrush&lt;/span&gt; &lt;span class="n"&gt;brush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;PdfPen&lt;/span&gt; &lt;span class="n"&gt;borderPen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Create the PdfPath &lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;diameter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cornerRadius&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;SizeF&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SizeF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diameter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;diameter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;RectangleF&lt;/span&gt; &lt;span class="n"&gt;arc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RectangleF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;PdfPath&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfPath&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddArc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;180&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;arc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Right&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;diameter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddArc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;270&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;arc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bottom&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;diameter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddArc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;arc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddArc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CloseFigure&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;graphics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DrawPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;borderPen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;brush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the code above will produce the following PDF document with a stamp.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FPDF-page-with-dynamic-stamp-annotations-1024x633.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FPDF-page-with-dynamic-stamp-annotations-1024x633.png" alt="PDF page with dynamic stamp annotations" width="800" height="494"&gt;&lt;/a&gt;&lt;br&gt;PDF page with dynamic stamp annotations
  &lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a stamp with an image
&lt;/h2&gt;

&lt;p&gt;Image stamps are ideal for adding visual identity to invoices, reports, or official documents, ensuring they stand out and remain recognizable across workflows. Use your logo or a pre-rendered badge as a stamp to reinforce branding and professionalism.&lt;/p&gt;

&lt;p&gt;Here’s the code example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Load the existing PDF document&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfLoadedDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfLoadedDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../../../../data/input.pdf"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//Get the first page of the document&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfLoadedPage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// Position/size (points). Adjust to your layout.&lt;/span&gt;
    &lt;span class="n"&gt;RectangleF&lt;/span&gt; &lt;span class="n"&gt;bounds&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RectangleF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;250&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;162&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//Create rubber stamp annotation&lt;/span&gt;
    &lt;span class="n"&gt;PdfRubberStampAnnotation&lt;/span&gt; &lt;span class="n"&gt;stampAnnotation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfRubberStampAnnotation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"image stamp"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//Set author&lt;/span&gt;
    &lt;span class="n"&gt;stampAnnotation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Author&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"John Smith"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;//Get the appearance graphics of the stamp annotation&lt;/span&gt;
    &lt;span class="n"&gt;PdfGraphics&lt;/span&gt; &lt;span class="n"&gt;graphics&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stampAnnotation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Appearance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Normal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Graphics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;//Draw the image in the appearance graphics&lt;/span&gt;
    &lt;span class="n"&gt;PdfBitmap&lt;/span&gt; &lt;span class="n"&gt;stampImage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfBitmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;FileStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../../../../data/stamp.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FileMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FileAccess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;//Draw the image to the stamp appearance&lt;/span&gt;
    &lt;span class="n"&gt;graphics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DrawImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stampImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RectangleF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Height&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;//Add annotation to the page&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Annotations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stampAnnotation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//Save the document&lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"image-stamp.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The image below shows how the image stamp looks in the PDF.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FPDF-page-with-image-stamp-annotations-1-1024x643.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FPDF-page-with-image-stamp-annotations-1-1024x643.png" alt="PDF page with image stamp annotations" width="800" height="502"&gt;&lt;/a&gt;&lt;br&gt;PDF page with image stamp annotations
  &lt;/p&gt;

&lt;h2&gt;
  
  
  Customize stamp
&lt;/h2&gt;

&lt;p&gt;You can fully style a PDF stamp (rubber stamp annotation) by drawing a custom appearance with fonts, colors, borders, rotation, and opacity. This allows you to create branded stamps such as &lt;strong&gt;APPROVED&lt;/strong&gt;, &lt;strong&gt;PAID&lt;/strong&gt;, or &lt;strong&gt;CONFIDENTIAL&lt;/strong&gt; with a consistent visual identity.&lt;/p&gt;

&lt;p&gt;Code example for quick integration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Load the existing PDF document&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfLoadedDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfLoadedDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../../../../data/input.pdf"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//Get the first page of the document&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfLoadedPage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;//Create a rubberstamp annotation&lt;/span&gt;
    &lt;span class="n"&gt;PdfRubberStampAnnotation&lt;/span&gt; &lt;span class="n"&gt;draftStamp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfRubberStampAnnotation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RectangleF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;567&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;49&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//Set the author name&lt;/span&gt;
        &lt;span class="n"&gt;Author&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"John Smith"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;//Set the subject&lt;/span&gt;
        &lt;span class="n"&gt;Subject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Document Approval"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;//Set the opacity&lt;/span&gt;
        &lt;span class="n"&gt;Opacity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.75f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;//Set the stamp text&lt;/span&gt;
        &lt;span class="n"&gt;Text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Draft By John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;//Set the stamp icon&lt;/span&gt;
        &lt;span class="n"&gt;Icon&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfRubberStampAnnotationIcon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Draft&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;//Set the appearance as true to view the stamp icon across PDF viewers&lt;/span&gt;
    &lt;span class="n"&gt;draftStamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetAppearance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//Add annotation to the page&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Annotations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;draftStamp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//Create a rubberstamp annotation&lt;/span&gt;
    &lt;span class="n"&gt;PdfRubberStampAnnotation&lt;/span&gt; &lt;span class="n"&gt;rejectedStamp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfRubberStampAnnotation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RectangleF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;296&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;567&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;49&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//Set the author name&lt;/span&gt;
        &lt;span class="n"&gt;Author&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Milton"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;//Set the subject&lt;/span&gt;
        &lt;span class="n"&gt;Subject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Document Approval"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;//Set the stamp text&lt;/span&gt;
        &lt;span class="n"&gt;Text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Rejected By Milton"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;//Set the stamp icon&lt;/span&gt;
        &lt;span class="n"&gt;Icon&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfRubberStampAnnotationIcon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NotApproved&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;//Set the appearance as true to view the stamp icon across PDF viewers&lt;/span&gt;
    &lt;span class="n"&gt;rejectedStamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetAppearance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//Add annotation to the page&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Annotations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rejectedStamp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//Rotate the stamp annotation&lt;/span&gt;
    &lt;span class="n"&gt;PdfRubberStampAnnotation&lt;/span&gt; &lt;span class="n"&gt;confidentialStamp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfRubberStampAnnotation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RectangleF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;202&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;260&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;260&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;260&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//Set the author name&lt;/span&gt;
        &lt;span class="n"&gt;Author&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Sarah"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;//Set the subject&lt;/span&gt;
        &lt;span class="n"&gt;Subject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Confidential"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;//Set the stamp text&lt;/span&gt;
        &lt;span class="n"&gt;Text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Confidential By Sarah"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;//Get stamp appearance graphics&lt;/span&gt;
    &lt;span class="n"&gt;PdfGraphics&lt;/span&gt; &lt;span class="n"&gt;graphics&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;confidentialStamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Appearance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Normal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Graphics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;//Create a font&lt;/span&gt;
    &lt;span class="n"&gt;PdfFont&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfTrueTypeFont&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../../../../data/MomoTrustDisplay-Regular.ttf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PdfFontStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Regular&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//Create a brush&lt;/span&gt;
    &lt;span class="n"&gt;PdfBrush&lt;/span&gt; &lt;span class="n"&gt;brush&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfSolidBrush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Red&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//Create a pen&lt;/span&gt;
    &lt;span class="n"&gt;PdfPen&lt;/span&gt; &lt;span class="n"&gt;pen&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfPen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DarkBlue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;graphics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;//Move the graphics origin to the center of the stamp&lt;/span&gt;
    &lt;span class="n"&gt;graphics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TranslateTransform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;confidentialStamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bounds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Width&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;confidentialStamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bounds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Height&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//Rotate the graphics&lt;/span&gt;
    &lt;span class="n"&gt;graphics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RotateTransform&lt;/span&gt;&lt;span class="p"&gt;(-&lt;/span&gt;&lt;span class="m"&gt;45&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//Measure the text size&lt;/span&gt;
    &lt;span class="n"&gt;SizeF&lt;/span&gt; &lt;span class="n"&gt;textSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MeasureString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CONFIDENTIAL"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;PointF&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PointF&lt;/span&gt;&lt;span class="p"&gt;(-&lt;/span&gt;&lt;span class="n"&gt;textSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Width&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;textSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Height&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//Draw the text&lt;/span&gt;
    &lt;span class="n"&gt;graphics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DrawString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CONFIDENTIAL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;brush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//Draw a rounded corner rectangle&lt;/span&gt;
    &lt;span class="nf"&gt;DrawRoundedCornerRectangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RectangleF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;textSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Width&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;textSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Height&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;graphics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;graphics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Restore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;//Add annotation to the page&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Annotations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;confidentialStamp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//Save the document&lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"customize-stamp.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s what the PDF with a custom stamp looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FPDF-page-with-customized-stamp-1024x643.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FPDF-page-with-customized-stamp-1024x643.png" alt="PDF page with customized stamp" width="800" height="502"&gt;&lt;/a&gt;&lt;br&gt;PDF page with customized stamp
  &lt;/p&gt;

&lt;h2&gt;
  
  
  Remove stamps in PDF
&lt;/h2&gt;

&lt;p&gt;Removing the stamp annotation is useful when updating document status or cleaning drafts. You can remove stamps by navigating page annotations.&lt;/p&gt;

&lt;p&gt;Add this to your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Load the existing PDF document&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfLoadedDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfLoadedDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../../../../data/customize-stamp.pdf"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//Get the first page of the document&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfLoadedPage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;//Iterate the annotations and get stamp annotations&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfLoadedAnnotation&lt;/span&gt; &lt;span class="n"&gt;annotation&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Annotations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;annotation&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;PdfLoadedRubberStampAnnotation&lt;/span&gt; &lt;span class="n"&gt;stampAnnotation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;//Flatten the stamp annotation&lt;/span&gt;
            &lt;span class="n"&gt;stampAnnotation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Flatten&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;//Save the document&lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"flattened-samp_-nnotation.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the code, you’ll see this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FPDF-page-with-removed-stamp-annotations-1024x538.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FPDF-page-with-removed-stamp-annotations-1024x538.png" alt="PDF page with removed stamp annotations" width="800" height="420"&gt;&lt;/a&gt;&lt;br&gt;PDF page with removed stamp annotations
  &lt;/p&gt;

&lt;h2&gt;
  
  
  Flatten stamp
&lt;/h2&gt;

&lt;p&gt;Flatten converts a stamp into static page content, making it permanent and non-editable. To flatten a stamp, render its appearance directly onto the page, then remove the original annotations.&lt;/p&gt;

&lt;p&gt;Here’s how you can do it in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Load the existing PDF document&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfLoadedDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfLoadedDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../../../../data/customize-stamp.pdf"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//Get the first page of the document&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfLoadedPage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;//Create a list to hold annotations to be removed&lt;/span&gt;
    &lt;span class="n"&gt;List&lt;/span&gt; &lt;span class="n"&gt;annotationsToRemove&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;List&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;//Iterate the annotations and get stamp annotations&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfLoadedAnnotation&lt;/span&gt; &lt;span class="n"&gt;annotation&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Annotations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;annotation&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;PdfLoadedRubberStampAnnotation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;//Add the stamp annotation to the list for removal&lt;/span&gt;
            &lt;span class="n"&gt;annotationsToRemove&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;annotation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;//Remove the stamp annotations from the page&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;annotation&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;annotationsToRemove&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Annotations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;annotation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;//Save the document&lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"removed-stamp-annotation.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following image shows the before‑and‑after results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FPDF-page-with-flattened-stamp-1024x541.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FPDF-page-with-flattened-stamp-1024x541.png" alt="PDF page with flattened stamp" width="800" height="422"&gt;&lt;/a&gt;&lt;br&gt;PDF page with flattened stamp
  &lt;/p&gt;

&lt;h2&gt;
  
  
  Real-world use cases for PDF stamps
&lt;/h2&gt;

&lt;p&gt;Below are several practical scenarios that show how PDF stamping enhances automation, accuracy, and workflow clarity across different systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Automated approval stamping in a document management system
&lt;/h3&gt;

&lt;p&gt;A company using a web‑based Document Management System ( &lt;strong&gt;DMS&lt;/strong&gt; ) often needs to track internal approvals. When a manager reviews and approves a document, the system automatically applies an Approved stamp, complete with the reviewer’s name and timestamp, to the first page of the PDF before archiving it. This ensures every approved document enters the repository with clear, traceable metadata.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workflow integration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Trigger&lt;/strong&gt;: Manager clicks Approve in the DMS interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backend process (using Syncfusion’s PDF library)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load the selected PDF.&lt;/li&gt;
&lt;li&gt;Create a rubber stamp annotation with dynamic content.&lt;/li&gt;
&lt;li&gt;Insert the reviewer’s name and timestamp.&lt;/li&gt;
&lt;li&gt;Save the stamped PDF to the archive folder.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Provides complete auditability with reviewer identity and approval time.&lt;/li&gt;
&lt;li&gt;Eliminates manual stamping errors.&lt;/li&gt;
&lt;li&gt;Integrates smoothly with existing approval logic.&lt;/li&gt;
&lt;li&gt;Supports flattening for secure, long‑term archival.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Invoice status stamping in an accounting system
&lt;/h3&gt;

&lt;p&gt;A logistics company creates PDF invoices for each shipment. To streamline financial communication, their backend accounting system automatically stamps each invoice with its current payment status, &lt;strong&gt;PAID&lt;/strong&gt;, &lt;strong&gt;DUE&lt;/strong&gt;, or &lt;strong&gt;OVERDUE&lt;/strong&gt;, based on real‑time accounting data. The stamped invoice is then emailed directly to the client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow integration
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Trigger:&lt;/strong&gt; Payment status changes in the accounting database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backend process (using Syncfusion’s PDF library)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load the invoice PDF.&lt;/li&gt;
&lt;li&gt;Apply a color‑coded stamp (e.g., &lt;strong&gt;green&lt;/strong&gt; for &lt;strong&gt;PAID&lt;/strong&gt;, red for &lt;strong&gt;OVERDUE&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;Save the updated PDF and attach it to an automated email.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Automates client communication about payment status.&lt;/li&gt;
&lt;li&gt;Reduces manual processing errors and improves transparency.&lt;/li&gt;
&lt;li&gt;Provides a clear visual cue for both internal teams and customers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Legal filing status stamping in a case management system
&lt;/h3&gt;

&lt;p&gt;A law firm relies on a backend case management system to generate, file, and store legal documents. When a document is filed, served, or marked confidential, the system automatically applies the appropriate status stamp, along with metadata such as case ID and filing date, before submission to the court or archival.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workflow integration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Trigger&lt;/strong&gt;: A case status changes or a new document is uploaded for filing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backend process (using Syncfusion’s PDF library)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load the legal document PDF.&lt;/li&gt;
&lt;li&gt;Add a stamp such as &lt;strong&gt;Filed&lt;/strong&gt;, &lt;strong&gt;Served&lt;/strong&gt;, or &lt;strong&gt;Confidential&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Include case identifiers and filing dates for traceability.&lt;/li&gt;
&lt;li&gt;Save and archive the stamped document or submit it to the court portal.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ensures legal traceability and supports filing compliance.&lt;/li&gt;
&lt;li&gt;Automates labeling for court submissions.&lt;/li&gt;
&lt;li&gt;Reduces manual effort and increases operational efficiency.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  GitHub reference
&lt;/h2&gt;

&lt;p&gt;You can find the complete sample for adding stamps to a PDF using C# in our &lt;a href="https://github.com/SyncfusionExamples/add-or-remove-pdf-stamp-csharp" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How do I stamp every page (or only specific pages)?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Loop through the document pages and add the stamp only when the desired condition is met (for example, first page only, odd-numbered pages, or pages containing specific text).&lt;br&gt;&lt;br&gt;
This keeps your stamping logic centralized, flexible, and predictable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I position the stamp relative to the page (top-right, bottom-left) instead of using hardcoded coordinates?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use the page size to calculate positions dynamically. For example: &lt;strong&gt;x = page.Size.Width – stampWidth – margin&lt;/strong&gt; and &lt;strong&gt;y = margin&lt;/strong&gt;. This approach is especially important for PDFs with mixed page sizes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How can I make the stamp non-editable by end users?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Flatten the stamp so it becomes part of the page content.&lt;br&gt;&lt;br&gt;
If you leave it as an annotation, most PDF viewers will allow selecting, moving, or deleting it, depending on the PDF’s security permissions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I remove only the stamps that I added (without deleting other annotations)?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Assign a unique identifier, such as &lt;strong&gt;Author&lt;/strong&gt;, &lt;strong&gt;Subject&lt;/strong&gt;, or a distinctive &lt;strong&gt;Text&lt;/strong&gt; value, when creating the stamp.&lt;/p&gt;

&lt;p&gt;Then filter the page annotations by that metadata when iterating through them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I add stamps to password-protected PDFs?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, as long as you have the correct password and the document’s security settings allow modifications.&lt;/p&gt;

&lt;p&gt;If annotation permissions are restricted, adding or removing stamps may be blocked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What measurement units does RectangleF use for stamp bounds?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RectangleF coordinates and sizes use &lt;strong&gt;PDF points&lt;/strong&gt;, where: &lt;strong&gt;1 point = 1/72 inch&lt;/strong&gt;. If you need physical alignment (e.g., a 1-inch margin), convert inches to points by multiplying the value by 72.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thanks for reading! PDF stamps are more than just visual markers; they’re powerful tools for streamlining workflows, reinforcing brand identity, and ensuring auditability. Whether you’re adding standard icons, dynamic metadata, or image‑based logos, the &lt;a href="https://www.syncfusion.com/document-sdk/net-pdf-library" rel="noopener noreferrer"&gt;Syncfusion .NET PDF library&lt;/a&gt; gives you flexible, developer‑friendly APIs to handle it all. By applying these methods, you can make your document workflows more professional, efficient, and reliable.&lt;/p&gt;

&lt;p&gt;Explore our PDF library’s &lt;a href="https://help.syncfusion.com/document-processing/pdf/pdf-library/net/working-with-annotations" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; to unlock advanced stamp features and best practices.&lt;/p&gt;

&lt;p&gt;If you’re a Syncfusion user, you can download the setup from the &lt;a href="https://www.syncfusion.com/account" rel="noopener noreferrer"&gt;license and downloads&lt;/a&gt; page. Otherwise, you can download a free &lt;a href="https://www.syncfusion.com/downloads/" rel="noopener noreferrer"&gt;30-day trial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also contact us through our &lt;a href="https://www.syncfusion.com/forums" rel="noopener noreferrer"&gt;support forum&lt;/a&gt;, &lt;a href="https://www.syncfusion.com/feedback" rel="noopener noreferrer"&gt;feedback portal&lt;/a&gt;, or &lt;a href="https://support.syncfusion.com/" rel="noopener noreferrer"&gt;support portal&lt;/a&gt; for queries. We are always happy to assist you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Blogs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/add-update-hyperlinks-in-pdf-csharp" rel="noopener noreferrer"&gt;How to Add, Edit, or Remove Hyperlinks in PDFs Using C#?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/navigate-pdf-pages-csharp" rel="noopener noreferrer"&gt;5 Effective Ways to Navigate PDF Pages in C# Using .NET PDF Library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/add-remove-watermark-pdf-csharp" rel="noopener noreferrer"&gt;Step-by-Step Guide to Adding and Removing Watermarks in PDF using C#&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/add-remove-attachment-pdf-csharp" rel="noopener noreferrer"&gt;Easily Add and Remove Attachments in Your PDF Documents Using C#&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally published at &lt;a href="https://www.syncfusion.com/blogs/post/3-ways-add-stamp-pdf-csharp" rel="noopener noreferrer"&gt;Syncfusion.com.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>pdf</category>
      <category>netdevelopment</category>
      <category>csharp</category>
      <category>documentprocessing</category>
    </item>
    <item>
      <title>AI-Powered Smart TextArea for ASP.NET Core: Smarter Typing with Intelligent Autocompletion</title>
      <dc:creator>Phinter Atieno</dc:creator>
      <pubDate>Tue, 03 Feb 2026 05:06:16 +0000</pubDate>
      <link>https://forem.com/syncfusion/ai-powered-smart-textarea-for-aspnet-core-smarter-typing-with-intelligent-autocompletion-1cho</link>
      <guid>https://forem.com/syncfusion/ai-powered-smart-textarea-for-aspnet-core-smarter-typing-with-intelligent-autocompletion-1cho</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Syncfusion ASP.NET Core Smart TextArea component is introduced in the 2025 Volume 4 release. It brings AI‑powered sentence‑level autocompletions to your apps. It integrates seamlessly with OpenAI, Azure OpenAI, or Ollama to deliver smart, context‑aware suggestions that enhance writing workflows and boost overall productivity.&lt;/p&gt;

&lt;p&gt;As developers, we’re always looking for ways to enhance productivity and deliver smoother, more intuitive user experiences. &lt;a href="https://www.syncfusion.com/aspnet-core-ui-controls" rel="noopener noreferrer"&gt;Syncfusion&lt;sup&gt;®&lt;/sup&gt; ASP.NET Core UI Controls&lt;/a&gt; already provide a strong toolkit for building modern, high‑performance applications, and with the introduction of the new &lt;a href="https://www.syncfusion.com/aspnet-core-ui-controls/smart-textarea" rel="noopener noreferrer"&gt;Smart TextArea&lt;/a&gt;, things get even better.&lt;/p&gt;

&lt;p&gt;Released in the &lt;a href="https://www.syncfusion.com/forums/197921/essential-studio-2025-volume-4-main-release-v32-1-19-is-available-for-download" rel="noopener noreferrer"&gt;2025 Volume 4&lt;/a&gt; update, the Smart TextArea brings AI‑assisted writing directly into your ASP.NET Core apps.&lt;/p&gt;

&lt;p&gt;In this guide, we’ll explore what the Smart TextArea offers and how to integrate it into your app. We’ll also learn how to connect the control to &lt;a href="https://azure.microsoft.com/en-us/products/ai-foundry/models/openai?msockid=3e567114681e6bd934bb6732699c6a43" rel="noopener noreferrer"&gt;Azure OpenAI&lt;/a&gt; &lt;strong&gt;,&lt;/strong&gt; &lt;a href="https://openai.com/" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt; &lt;strong&gt;,&lt;/strong&gt; or &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; to power real‑time, sentence‑level autocompletions.&lt;/p&gt;

&lt;p&gt;Ready to enhance your users’ writing workflow? Let’s get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Smart TextArea matters
&lt;/h2&gt;

&lt;p&gt;A standard textarea allows basic text entry, but nothing more. The Smart TextArea changes this by introducing intelligent, AI‑driven writing assistance directly within the editing experience.&lt;/p&gt;

&lt;p&gt;With sentence‑level autocompletions based on your configuration and the user’s input, the Smart TextArea helps users write faster, communicate more clearly, and reduce repetitive typing. Whether someone is replying to an issue, drafting an email, or participating in a chat, the control becomes a helpful writing companion that improves productivity with every keystroke.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI‑powered sentence completion&lt;/strong&gt;: Provides context‑aware predictions to help users finish sentences efficiently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customizable suggestions&lt;/strong&gt;: Supports both predefined phrases and AI‑generated completions tailored to technical, conversational, or customer‑support contexts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real‑time assistance&lt;/strong&gt;: Offers instant suggestions to improve clarity, reduce errors, and accelerate content creation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seamless integration&lt;/strong&gt;: Easily integrates into ASP.NET Core apps to deliver AI‑assisted writing across text‑based workflows.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://ej2.syncfusion.com/aspnetcore/documentation/smart-textarea/getting-started" rel="noopener noreferrer"&gt;Smart TextArea&lt;/a&gt; for ASP.NET Core enhances the standard textarea by applying real‑time, AI‑driven analysis to the user’s input.&lt;/p&gt;

&lt;p&gt;Here’s what happens behind the scenes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The control monitors what the user is typing and detects context based on previous words or phrases.&lt;/li&gt;
&lt;li&gt;It checks for predefined suggestions that you configure.&lt;/li&gt;
&lt;li&gt;When enabled, it sends the user’s partial text to the connected AI model.&lt;/li&gt;
&lt;li&gt;The model generates the most suitable sentence‑level continuation.&lt;/li&gt;
&lt;li&gt;The Smart TextArea displays several potential completions, and the user can accept or refine them instantly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This creates a smooth, intelligent writing experience, especially useful in communication‑heavy workflows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example scenarios
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Typing &lt;strong&gt;“To investigate”&lt;/strong&gt; in a GitHub issue reply may prompt “We will need a reproducible example as a public Git repository.”&lt;/li&gt;
&lt;li&gt;Entering &lt;strong&gt;“Hello!”&lt;/strong&gt; in a customer support chat may prompt: “How can I assist you today?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These context‑aware completions help users reduce repetitive phrasing and maintain consistent communication quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started with the ASP.NET Core Smart TextArea component
&lt;/h2&gt;

&lt;p&gt;Now that we’ve seen what the Smart TextArea can do, let’s walk through how to integrate it into your ASP.NET Core app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before you begin, ensure you have the following installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; .&lt;a href="https://dotnet.microsoft.com/en-us/download/dotnet/8.0" rel="noopener noreferrer"&gt;NET 8&lt;/a&gt; or later.&lt;/li&gt;
&lt;li&gt;A new or existing &lt;strong&gt;ASP.NET Core&lt;/strong&gt; application.&lt;/li&gt;
&lt;li&gt;An &lt;a href="https://help.openai.com/en/articles/4936850-where-do-i-find-my-openai-api-key" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt; / &lt;a href="https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/create-resource" rel="noopener noreferrer"&gt;Azure OpenAI Account&lt;/a&gt;, or Ollama environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Create a new ASP.NET Core project
&lt;/h3&gt;

&lt;p&gt;Start by creating a new ASP.NET Core project using Visual Studio via &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/tutorials/razor-pages/razor-pages-start?view=aspnetcore-9.0&amp;amp;tabs=visual-studio#create-a-razor-pages-web-app" rel="noopener noreferrer"&gt;Microsoft Templates&lt;/a&gt; or the &lt;a href="https://ej2.syncfusion.com/aspnetcore/documentation/visual-studio-integration/create-project" rel="noopener noreferrer"&gt;Syncfusion ASP.NET Core Extension&lt;/a&gt;&lt;u&gt;&lt;/u&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Install Syncfusion ASP.NET Core NuGet package
&lt;/h3&gt;

&lt;p&gt;To add the Smart TextArea control to your ASP.NET Core app, install the &lt;a href="https://www.nuget.org/packages/Syncfusion.EJ2.AspNet.Core/" rel="noopener noreferrer"&gt;Syncfusion.EJ2.AspNet.Core&lt;/a&gt; NuGet package.&lt;/p&gt;

&lt;p&gt;You can install it in Visual Studio:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;Tools&lt;/strong&gt; → &lt;strong&gt;NuGet Package Manager&lt;/strong&gt; → &lt;strong&gt;Manage NuGet Packages for Solution&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;Syncfusion.EJ2.AspNet.Core&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Install the package into your project.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you prefer using the Package Manager Console, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
Install-Package Syncfusion.EJ2.AspNet.Core &lt;span class="nt"&gt;-Version&lt;/span&gt; 32.1.19
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Add Syncfusion ASP.NET Core Tag Helper
&lt;/h3&gt;

&lt;p&gt;Now, we need to enable the Syncfusion Tag Helper to use the Smart TextArea in our Razor pages.&lt;/p&gt;

&lt;p&gt;Open the &lt;code&gt;~/Pages/_ViewImports.cshtml&lt;/code&gt; file and add the following code in it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;@addTagHelper &lt;span class="k"&gt;*&lt;/span&gt;, Syncfusion.EJ2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Add stylesheet and script resources
&lt;/h3&gt;

&lt;p&gt;Next, reference the required Syncfusion CSS and JavaScript files in your layout.&lt;/p&gt;

&lt;p&gt;Edit the &lt;code&gt;~/Pages/Shared/_Layout.cshtml&lt;/code&gt; file and include the following code inside the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    ...
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.syncfusion.com/ej2/32.1.19/fluent2.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.syncfusion.com/ej2/32.1.19/dist/ej2.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Configure AI service
&lt;/h3&gt;

&lt;p&gt;The Smart TextArea for ASP.NET Core relies on an AI provider to generate sentence‑level completions. We can connect it to &lt;strong&gt;OpenAI&lt;/strong&gt;, &lt;strong&gt;Azure OpenAI&lt;/strong&gt;, or &lt;strong&gt;Ollama&lt;/strong&gt;, depending on our app’s requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 1: Configure OpenAI
&lt;/h3&gt;

&lt;p&gt;Create an OpenAI API key and assign it to &lt;code&gt;openAIApiKey&lt;/code&gt; value in your configuration. Then, specify the model you want the Smart TextArea to use, such as &lt;code&gt;gpt‑3.5‑turbo, gpt‑4&lt;/code&gt;, or any other supported model, by setting the &lt;code&gt;openAIModel&lt;/code&gt; value.&lt;/p&gt;

&lt;p&gt;Install the following NuGet packages into your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
Install-Package Microsoft.Extensions.AI
Install-Package Microsoft.Extensions.AI.OpenAI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To configure the &lt;strong&gt;OpenAI&lt;/strong&gt; service, add the following settings to the &lt;code&gt;~/Program.cs&lt;/code&gt; file in your ASP.NET Core app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;using&lt;/span&gt; &lt;span class="nx"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;using&lt;/span&gt; &lt;span class="nx"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;using&lt;/span&gt; &lt;span class="nx"&gt;Syncfusion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EJ2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;
&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;
&lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AddRazorPages&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="nx"&gt;openAIApiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;API-KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="nx"&gt;openAIModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OPENAI_MODEL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;OpenAIClient&lt;/span&gt; &lt;span class="nx"&gt;openAIClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAIClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;openAIApiKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;IChatClient&lt;/span&gt; &lt;span class="nx"&gt;openAIChatClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;openAIClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GetChatClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;openAIModel&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nc"&gt;AsIChatClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AddChatClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;openAIChatClient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AddSyncfusionSmartComponents&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;InjectOpenAIInference&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;.....&lt;/span&gt;
&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option 2: Configure Azure OpenAI
&lt;/h3&gt;

&lt;p&gt;Before setting up &lt;strong&gt;Azure OpenAI&lt;/strong&gt;, deploy an Azure OpenAI Service &lt;a href="https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/create-resource" rel="noopener noreferrer"&gt;resource&lt;/a&gt; and the model you plan to use.&lt;/p&gt;

&lt;p&gt;Once deployed, Azure will provide the required values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;azureOpenAIKey&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;azureOpenAIEndpoint&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;azureOpenAIModel&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install the following NuGet packages into your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
Install-Package Microsoft.Extensions.AI
Install-Package Microsoft.Extensions.AI.OpenAI
Install-Package Azure.AI.OpenAI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To configure the AI service, add the following settings to the &lt;code&gt;~/Program.cs&lt;/code&gt; file in your ASP.NET Core app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;using&lt;/span&gt; &lt;span class="nx"&gt;Syncfusion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EJ2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;using&lt;/span&gt; &lt;span class="nx"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;using&lt;/span&gt; &lt;span class="nx"&gt;Azure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;using&lt;/span&gt; &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ClientModel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;
&lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AddRazorPages&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="nx"&gt;azureOpenAIKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AZURE_OPENAI_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="nx"&gt;azureOpenAIEndpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AZURE_OPENAI_ENDPOINT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="nx"&gt;azureOpenAIModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AZURE_OPENAI_MODEL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;AzureOpenAIClient&lt;/span&gt; &lt;span class="nx"&gt;azureOpenAIClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AzureOpenAIClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;azureOpenAIEndpoint&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
     &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApiKeyCredential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;azureOpenAIKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;IChatClient&lt;/span&gt; &lt;span class="nx"&gt;azureOpenAIChatClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azureOpenAIClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GetChatClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;azureOpenAIModel&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nc"&gt;AsIChatClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AddChatClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;azureOpenAIChatClient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AddSyncfusionSmartComponents&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;InjectOpenAIInference&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;.....&lt;/span&gt;
&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option 3: Ollama
&lt;/h3&gt;

&lt;p&gt;To use Ollama for running self-hosted models:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Download and install Ollama&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Visit &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama’s official website&lt;/a&gt; and install the appropriate app for your operating system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Install the desired model from the Ollama library&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Browse the available models in the &lt;a href="https://ollama.com/library" rel="noopener noreferrer"&gt;Ollama Model Library&lt;/a&gt; and install the one that works for you, such as &lt;strong&gt;llama2:13b&lt;/strong&gt;, &lt;strong&gt;mistral:7b&lt;/strong&gt;, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Configure your application&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Update your app settings to point to your local Ollama server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Endpoint:&lt;/strong&gt; Set the endpoint URL to where Ollama is running, typically: &lt;a href="http://localhost:11434" rel="noopener noreferrer"&gt;http://localhost:11434&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ModelName:&lt;/strong&gt; specify the exact model name you installed, such as &lt;strong&gt;llama2:13b&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Install the required NuGet package&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Install the necessary NuGet dependencies in your project to enable communication with the Ollama runtime.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Install-Package Microsoft.Extensions.AI
Install-Package OllamaSharp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following settings to the &lt;code&gt;~/Program.cs&lt;/code&gt; file in your ASP.NET Core app.&lt;/p&gt;

&lt;p&gt;JavaScript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;using&lt;/span&gt; &lt;span class="nx"&gt;Syncfusion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EJ2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;using&lt;/span&gt; &lt;span class="nx"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;using&lt;/span&gt; &lt;span class="nx"&gt;OllamaSharp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AddRazorPages&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="nx"&gt;ModelName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MODEL_NAME&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;IChatClient&lt;/span&gt; &lt;span class="nx"&gt;chatClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OllamaApiClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:11434&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ModelName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AddChatClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chatClient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AddSyncfusionSmartComponents&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;InjectOpenAIInference&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;....&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6: Add ASP.NET Core Smart TextArea Control
&lt;/h3&gt;

&lt;p&gt;Finally, add the Syncfusion ASP.NET Core Smart TextArea tag helper in the &lt;strong&gt;&lt;code&gt;~/Pages/Index.cshtml&lt;/code&gt;&lt;/strong&gt; page, as shown in the code example below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;@{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;presets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;userRole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Maintainer of an open-source project replying to GitHub issues&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;userPhrases&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thank you for contacting us.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;To investigate, we'll need a repro as a public Git repo.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Could you please post a screenshot of NEED_INFO?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This sounds like a usage question. This issue tracker is intended for bugs and feature proposals. Unfortunately, we don't have the capacity to answer general usage questions and would recommend Stack Overflow for a faster response.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;We don't accept ZIP files as repros.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nx"&gt;placeHolder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Write your response to the GitHub issue...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ejs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;smarttextarea&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;smartTextarea&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@presets.userRole&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;phrases&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@presets.userPhrases&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;75%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@presets.placeHolder&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;floatLabelType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ejs-smarttextarea&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s review the attributes in the code example above.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;user-role&lt;/strong&gt;: This attribute is &lt;strong&gt;required&lt;/strong&gt; to define the autocompletion context based on the role of the person typing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;user-phrases&lt;/strong&gt;: This attribute is &lt;strong&gt;optional&lt;/strong&gt; and provides predefined expressions that align with the user/app’s tone and frequently used content.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Press &lt;strong&gt;Ctrl+F5 (Windows)&lt;/strong&gt; or &lt;strong&gt;⌘&lt;/strong&gt; &lt;strong&gt;+F5 (macOS)&lt;/strong&gt; to run the app. This will open your browser and display the Syncfusion ASP.NET Core Smart TextArea.&lt;/p&gt;

&lt;p&gt;Type &lt;strong&gt;Thank you&lt;/strong&gt; to see the sentence autocompletion feature in action, as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FASP.NET-Core-Smart-TextArea-with-autocompletion.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FASP.NET-Core-Smart-TextArea-with-autocompletion.gif" alt="ASP.NET Core Smart TextArea with autocompletion" width="1324" height="314"&gt;&lt;/a&gt;&lt;br&gt;ASP.NET Core Smart TextArea with autocompletion
  &lt;/p&gt;

&lt;h3&gt;
  
  
  Customizing the appearance of suggestions
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;show-suggestion-on-popup&lt;/code&gt; attribute in the ASP.NET Core Smart TextArea control determines how suggestions are presented to users. When this attribute is set to true, the Smart TextArea displays suggestions inside a pop-up panel.&lt;/p&gt;

&lt;p&gt;Try this in your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;@{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;presets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;userRole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Maintainer of an open-source project replying to GitHub issues&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;userPhrases&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thank you for contacting us.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;To investigate, we'll need a repro as a public Git repo.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Could you please post a screenshot of NEED_INFO?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This sounds like a usage question. This issue tracker is intended for bugs and feature proposals. Unfortunately, we don't have the capacity to answer general usage questions and would recommend Stack Overflow for a faster response.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;We don't accept ZIP files as repros.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nx"&gt;placeHolder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Write your response to the GitHub issue...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ejs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;smarttextarea&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;smartTextarea&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@presets.userRole&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;phrases&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@presets.userPhrases&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;75%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@presets.placeHolder&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;floatLabelType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;show&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;suggestion&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;popup&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ejs-smarttextarea&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s a quick demo of the feature in action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FSuggestions-displayed-on-the-popup.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.syncfusion.com%2Fblogs%2Fwp-content%2Fuploads%2F2026%2F02%2FSuggestions-displayed-on-the-popup.gif" alt="ASP.NET Core Smart TextArea displaying suggestions in a pop-up" width="1331" height="351"&gt;&lt;/a&gt;&lt;br&gt;ASP.NET Core Smart TextArea displaying suggestions in a pop-up
  &lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub reference
&lt;/h2&gt;

&lt;p&gt;You can also find the complete example for ASP.NET Core Smart TextArea on &lt;a href="https://github.com/syncfusion/smart-ai-samples/tree/master/aspnetcore" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thank you for reading! The &lt;a href="https://ej2.syncfusion.com/aspnetcore/smarttextarea/defaultfunctionalities#/fluent2" rel="noopener noreferrer"&gt;Syncfusion ASP.NET Core Smart TextArea&lt;/a&gt; released in the &lt;a href="https://www.syncfusion.com/forums/197921/essential-studio-2025-volume-4-main-release-v32-1-19-is-available-for-download" rel="noopener noreferrer"&gt;2025 Volume 4&lt;/a&gt; is a powerful AI-driven component designed to enhance text input efficiency and accuracy. With its intelligent sentence-level autocompletion, it transforms how users compose text, reducing typing effort and improving workflow efficiency. By integrating this control into your apps, you can streamline content creation, ensure consistent communication, and enhance the overall user experience.&lt;/p&gt;

&lt;p&gt;Check out Syncfusion AI solutions for &lt;a href="https://github.com/syncfusion/smart-ai-samples/?tab=readme-ov-file#included-platforms" rel="noopener noreferrer"&gt; Blazor, ASP.NET Core, Angular, React, Vue, and TypeScript/JavaScript&lt;/a&gt; platforms. You can also refer to our  &lt;a href="https://help.syncfusion.com/common/essential-studio/release-notes/v32.1.19" rel="noopener noreferrer"&gt;Release Notes&lt;/a&gt; and &lt;a href="https://www.syncfusion.com/products/whatsnew" rel="noopener noreferrer"&gt;What’s New&lt;/a&gt; pages to see the other updates in this release, and leave your feedback in the comments section below.&lt;/p&gt;

&lt;p&gt;If you’re a Syncfusion user, you can download the setup from the &lt;a href="https://www.syncfusion.com/account/downloads" rel="noopener noreferrer"&gt;license and downloads&lt;/a&gt; page. Otherwise, you can download a free &lt;a href="https://www.syncfusion.com/downloads" rel="noopener noreferrer"&gt;30-day tria&lt;/a&gt;&lt;a href="https://www.syncfusion.com/downloads/" rel="noopener noreferrer"&gt;l&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also contact us through our &lt;a href="https://www.syncfusion.com/forums" rel="noopener noreferrer"&gt;support forum&lt;/a&gt;, &lt;a href="https://support.syncfusion.com/" rel="noopener noreferrer"&gt;support portal&lt;/a&gt;, or &lt;a href="https://www.syncfusion.com/feedback" rel="noopener noreferrer"&gt;feedback portal&lt;/a&gt; for queries. We are always happy to assist you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Blogs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/build-a-pdf-viewer-editor-in-angular" rel="noopener noreferrer"&gt;Build a Full-Featured PDF Editor in Angular for Modern Web Apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/incremental-hydration-in-angular-apps" rel="noopener noreferrer"&gt;Incremental Hydration in Angular: Build SSR Apps That Feel Instantly Interactive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/react-angular-data-grid-row-pinning" rel="noopener noreferrer"&gt;How to Keep Important Rows Visible in Angular and React Data Grids&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/blogs/post/video-preview-in-angular-file-upload" rel="noopener noreferrer"&gt;How to Preview Videos Before Uploading Files in Angular File Upload&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally published at &lt;a href="https://www.syncfusion.com/blogs/post/ai-powered-smart-textarea-aspdotnetcore" rel="noopener noreferrer"&gt;Syncfusion.com.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aspnetcore</category>
      <category>netcore</category>
      <category>ai</category>
      <category>aipoweredsmartcontrol</category>
    </item>
  </channel>
</rss>
