<?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>DEV Community: Lucy Muturi</title>
    <description>The latest articles on DEV Community by Lucy Muturi (@lucy_muturi).</description>
    <link>https://dev.to/lucy_muturi</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1819420%2F87984bdb-83b5-40f8-8f70-9afbaec9a433.png</url>
      <title>DEV Community: Lucy Muturi</title>
      <link>https://dev.to/lucy_muturi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lucy_muturi"/>
    <language>en</language>
    <item>
      <title>ASP.NET Core Scheduler Features Every Developer Should Know</title>
      <dc:creator>Lucy Muturi</dc:creator>
      <pubDate>Mon, 27 Jul 2026 11:48:27 +0000</pubDate>
      <link>https://dev.to/syncfusion/aspnet-core-scheduler-features-every-developer-should-know-4g26</link>
      <guid>https://dev.to/syncfusion/aspnet-core-scheduler-features-every-developer-should-know-4g26</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Skip building scheduler logic from scratch. Syncfusion’s ASP.NET Core Scheduler delivers production-ready appointment management with recurring events, multi-timezone support, CRUD operations, flexible views, and multiple resources. All configured in hours, not weeks.&lt;/p&gt;

&lt;p&gt;Building a scheduling application sounds straightforward until you start dealing with recurring meetings, timezone differences, resource allocation, and appointment management. What begins as a simple calendar requirement can quickly become a complex project with countless edge cases.&lt;/p&gt;

&lt;p&gt;Instead of building scheduling functionality from scratch, you can leverage the Syncfusion &lt;a href="https://www.syncfusion.com/scheduler-sdk/aspnet-core-scheduler" rel="noopener noreferrer"&gt;ASP.NET Core Scheduler&lt;/a&gt; to handle these challenges out of the box. From managing recurring appointments to coordinating resources across teams, it provides the essential capabilities needed for modern scheduling applications.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore five core Scheduler features that help developers build robust scheduling solutions faster:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Appointments&lt;/li&gt;
&lt;li&gt;CRUD operations&lt;/li&gt;
&lt;li&gt;Timezone support&lt;/li&gt;
&lt;li&gt;Flexible views&lt;/li&gt;
&lt;li&gt;Multiple resources&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Appointments: The foundation of every scheduling application
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://ej2.syncfusion.com/aspnetcore/documentation/schedule/appointments" rel="noopener noreferrer"&gt;Appointments&lt;/a&gt; are at the heart of any scheduling system. Whether you’re building a meeting planner, appointment booking platform, or resource management solution, the ability to create and organize events efficiently is essential.&lt;/p&gt;

&lt;h3&gt;
  
  
  Support for different event types
&lt;/h3&gt;

&lt;p&gt;Not every event behaves the same way. Some occupy a specific time slot, while others span an entire day or repeat on a regular schedule.&lt;/p&gt;

&lt;p&gt;The Scheduler supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Standard appointments&lt;/code&gt;&lt;/strong&gt; for time-bound activities&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;All-day events&lt;/code&gt;&lt;/strong&gt; for holidays, conferences, or milestones&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Recurring events&lt;/code&gt;&lt;/strong&gt; for meetings that occur on a predictable schedule&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Multi-day events&lt;/code&gt;&lt;/strong&gt; that span several dates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, instead of creating a weekly team meeting dozens of times, you can define a recurrence rule once and let the Scheduler generate future occurrences automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;appointment&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;AppointmentData&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;"Weekly Standup"&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="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2024&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;15&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;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;EndTime&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;DateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2024&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;15&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;30&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;RecurrenceRule&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,WE,FR;COUNT=52"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;&lt;code&gt;RecurrenceRule&lt;/code&gt;&lt;/strong&gt; property follows &lt;strong&gt;&lt;code&gt;iCalendar&lt;/code&gt;&lt;/strong&gt; (RFC 5545) specification. You can set occurrences to end after N times (COUNT=52), on a specific date (UNTIL=20241231), or never end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spanned Events&lt;/strong&gt;  (duration &amp;gt; 24 hours) display in the all-day row by default. Configure &lt;strong&gt;&lt;code&gt;SpannedEventPlacement&lt;/code&gt;&lt;/strong&gt; to render them inside time slots instead, which is useful for multi-day projects visible in the working area.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom fields and validation
&lt;/h3&gt;

&lt;p&gt;Enforce data integrity by adding validation rules to each field. You can define validation rules directly in the Razor template using the &lt;strong&gt;&lt;code&gt;validationRules&lt;/code&gt;&lt;/strong&gt; attribute.&lt;/p&gt;

&lt;p&gt;You can also define reusable validation rule objects in your controller and reference them across multiple fields:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;validationRules&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;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&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;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"required"&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;locationRules&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;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&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;&amp;gt;&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"required"&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="s"&gt;"regex"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"^[a-zA-Z0-9-]*$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Special characters not allowed"&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;This approach allows you to centralize validation logic and reuse the same rules across multiple scheduler instances when needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prevention features
&lt;/h3&gt;

&lt;p&gt;Prevent overlapping events by setting &lt;strong&gt;&lt;code&gt;allowOverlap="false"&lt;/code&gt;&lt;/strong&gt;. The scheduler blocks conflicting event creation with an alert. This is critical for resource-constrained scenarios (meeting rooms, equipment).&lt;/p&gt;

&lt;p&gt;Block specific time ranges (unavailable slots, maintenance windows) using events with &lt;strong&gt;&lt;code&gt;isBlock="true"&lt;/code&gt;&lt;/strong&gt;. These appear visually distinct and prevent new appointments during those times.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. CRUD operations: Managing the complete appointment lifecycle
&lt;/h2&gt;

&lt;p&gt;A scheduling application is only useful if users can create, update, and remove appointments effortlessly.&lt;/p&gt;

&lt;p&gt;Our Scheduler includes built-in support for the entire appointment lifecycle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating events
&lt;/h3&gt;

&lt;p&gt;Users can create appointments directly within the interface by selecting a date or time slot and entering event details such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Subject&lt;/li&gt;
&lt;li&gt;Location&lt;/li&gt;
&lt;li&gt;Start time&lt;/li&gt;
&lt;li&gt;End time&lt;/li&gt;
&lt;li&gt;Recurrence settings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Developers can also create appointments programmatically when business workflows require automated scheduling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JavaScript&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;scheduleObj&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;schedule&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;ej2_instances&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;updatedEvent&lt;/span&gt; &lt;span class="o"&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;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Updated Team Meeting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;StartTime&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;EndTime&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&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="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;scheduleObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Server-side insert logic
&lt;/h3&gt;

&lt;p&gt;When appointments are created, the scheduler sends an insert action request. Your backend processes this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"insert"&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="k"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;DateTime&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;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="k"&gt;value&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;DateTime&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;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="k"&gt;value&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;appointment&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;ScheduleEventData&lt;/span&gt;&lt;span class="p"&gt;()&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="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScheduleEventDatas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&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="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;Subject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&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;StartTime&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;EndTime&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;IsAllDay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsAllDay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;RecurrenceRule&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RecurrenceRule&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScheduleEventDatas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;InsertOnSubmit&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SubmitChanges&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;
  
  
  Editing Appointments
&lt;/h3&gt;

&lt;p&gt;Schedules change constantly. Meetings get rescheduled, durations are adjusted, and locations change.&lt;/p&gt;

&lt;p&gt;The Scheduler makes it easy to edit existing appointments while preserving important metadata. You can edit appointments in 3 ways.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Normal events&lt;/strong&gt;: Double-click to edit, then save changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recurring events&lt;/strong&gt;: Events can be modified either as a single occurrence or as part of the entire series.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Method:&lt;/strong&gt; You can edit appointments programmatically using the &lt;strong&gt;&lt;code&gt;saveEvent&lt;/code&gt;&lt;/strong&gt; method.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;JavaScript&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;scheduleObj&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;schedule&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;ej2_instances&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;updatedEvent&lt;/span&gt; &lt;span class="o"&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;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Updated Team Meeting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;StartTime&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;EndTime&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&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="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;scheduleObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deleting Appointments
&lt;/h3&gt;

&lt;p&gt;Appointments can be removed individually or deleted as part of a recurring series. This flexibility helps maintain accurate schedules while reducing the complexity of managing event history.&lt;/p&gt;

&lt;p&gt;By handling these operations automatically, developers can spend less time building infrastructure and more time delivering business value.&lt;/p&gt;

&lt;p&gt;For more information, see how &lt;a href="https://ej2.syncfusion.com/aspnetcore/documentation/schedule/crud-actions" rel="noopener noreferrer"&gt;CRUD&lt;/a&gt; operations in the Scheduler support full appointment lifecycle management through multiple approaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Timezone support: Scheduling across location boundaries
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://ej2.syncfusion.com/aspnetcore/documentation/schedule/timezone" rel="noopener noreferrer"&gt;Timezone&lt;/a&gt; and localization support ensures accurate scheduling across regions. Syncfusion manages the time zone conversions automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scheduler-level timezones
&lt;/h3&gt;

&lt;p&gt;Organizations that operate from a central office often need all events displayed according to a single timezone.&lt;/p&gt;

&lt;p&gt;The Scheduler allows you to define a default &lt;strong&gt;&lt;code&gt;timezone&lt;/code&gt;&lt;/strong&gt; so every user sees appointments consistently, regardless of their local device settings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSHTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ejs-schedule&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"schedule"&lt;/span&gt; &lt;span class="na"&gt;timezone=&lt;/span&gt;&lt;span class="s"&gt;"America/New_York"&lt;/span&gt; &lt;span class="na"&gt;selectedDate=&lt;/span&gt;&lt;span class="s"&gt;"new DateTime(2024, 1, 15)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;e-schedule-eventsettings&lt;/span&gt; &lt;span class="na"&gt;dataSource=&lt;/span&gt;&lt;span class="s"&gt;"@ViewBag.appointments"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/e-schedule-eventsettings&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ejs-schedule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, every user sees appointments in Eastern Time, regardless of their local timezone. Useful for centralized operations like trading, broadcasts, or corporate headquarters scheduling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Event-level timezone
&lt;/h3&gt;

&lt;p&gt;Some applications require appointments to be tied to different geographic locations.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;A meeting in New York&lt;/li&gt;
&lt;li&gt;A training session in London&lt;/li&gt;
&lt;li&gt;A conference in Singapore&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each event can maintain its own timezone while the Scheduler automatically converts and displays the correct local time for every user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSHTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;e-schedule-eventsettings&lt;/span&gt; &lt;span class="na"&gt;dataSource=&lt;/span&gt;&lt;span class="s"&gt;"@ViewBag.appointments"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;e-eventsettings-fields&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"Id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;e-field-starttime&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"StartTime"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/e-field-starttime&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;e-field-starttimezone&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"StartTimeZone"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/e-field-starttimezone&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;e-field-endtimezone&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"EndTimeZone"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/e-field-endtimezone&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/e-eventsettings-fields&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/e-schedule-eventsettings&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An appointment at 9:00 AM in “America/Los_Angeles” displays as 12:00 PM for a “America/New_York” user (3-hour difference). The scheduler handles all conversion math automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  UTC-based scheduling
&lt;/h3&gt;

&lt;p&gt;For global systems, storing and displaying events using UTC provides an additional layer of consistency and helps eliminate timezone-related errors.&lt;/p&gt;

&lt;p&gt;This approach is particularly useful for enterprise applications serving distributed teams.&lt;/p&gt;

&lt;p&gt;In your &lt;strong&gt;&lt;code&gt;Startup.cs&lt;/code&gt;&lt;/strong&gt;, ensure JSON serialization uses UTC:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Startup.cs&lt;/strong&gt;&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="nf"&gt;AddJsonOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SerializerSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateTimeZoneHandling&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; 
    &lt;span class="n"&gt;DateTimeZoneHandling&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Utc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures server and client agree on time representation, preventing off-by-hour surprises.&lt;/p&gt;

&lt;h3&gt;
  
  
  Localization: Supporting multiple languages and cultures
&lt;/h3&gt;

&lt;p&gt;The Scheduler integrates &lt;a href="https://ej2.syncfusion.com/aspnetcore/documentation/schedule/localization" rel="noopener noreferrer"&gt;localization&lt;/a&gt; (globalization and language translation) to function globally. You can adapt the Scheduler to various languages and regions using the locale property.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSHTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ejs-schedule&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"schedule"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"550px"&lt;/span&gt; &lt;span class="na"&gt;locale=&lt;/span&gt;&lt;span class="s"&gt;"fr-CH"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;e-schedule-eventsettings&lt;/span&gt; &lt;span class="na"&gt;dataSource=&lt;/span&gt;&lt;span class="s"&gt;"@ViewBag.appointments"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/e-schedule-eventsettings&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ejs-schedule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Customize date format
&lt;/h3&gt;

&lt;p&gt;By default, Scheduler follows &lt;strong&gt;&lt;code&gt;"MM/dd/yyyy"&lt;/code&gt;&lt;/strong&gt; format based on the locale. Customize using the &lt;strong&gt;&lt;code&gt;dateFormat&lt;/code&gt;&lt;/strong&gt; property:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSHTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ejs-schedule&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"schedule"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"550px"&lt;/span&gt; &lt;span class="na"&gt;dateFormat=&lt;/span&gt;&lt;span class="s"&gt;"yyyy/MM/dd"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;e-schedule-eventsettings&lt;/span&gt; &lt;span class="na"&gt;dataSource=&lt;/span&gt;&lt;span class="s"&gt;"@ViewBag.appointments"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/e-schedule-eventsettings&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ejs-schedule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Set time format
&lt;/h3&gt;

&lt;p&gt;Control 12-hour or 24-hour format using &lt;strong&gt;&lt;code&gt;timeFormat&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSHTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ejs-schedule&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"schedule"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"550px"&lt;/span&gt; &lt;span class="na"&gt;timeFormat=&lt;/span&gt;&lt;span class="s"&gt;"HH:mm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;e-schedule-eventsettings&lt;/span&gt; &lt;span class="na"&gt;dataSource=&lt;/span&gt;&lt;span class="s"&gt;"@ViewBag.appointments"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/e-schedule-eventsettings&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ejs-schedule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enable Right-to-Left (RTL) mode
&lt;/h3&gt;

&lt;p&gt;For languages like Arabic or Hebrew, set &lt;strong&gt;&lt;code&gt;enableRtl="true"&lt;/code&gt;&lt;/strong&gt; to display the Scheduler layout from right to left:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSHTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ejs-schedule&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"schedule"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"550px"&lt;/span&gt; &lt;span class="na"&gt;enableRtl=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;e-schedule-eventsettings&lt;/span&gt; &lt;span class="na"&gt;dataSource=&lt;/span&gt;&lt;span class="s"&gt;"@ViewBag.appointments"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/e-schedule-eventsettings&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ejs-schedule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Localize static text
&lt;/h3&gt;

&lt;p&gt;Translate UI text (buttons, labels, messages) using the &lt;strong&gt;&lt;code&gt;L10n&lt;/code&gt;&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JavaScript&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;L10n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ej&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;L10n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;L10n&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hu&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;schedule&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;day&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;Nap&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;week&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;Hét&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;month&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;Hónap&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;today&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;Ma&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;noEvents&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;Nincs esemény&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;Localization enables teams across regions to work seamlessly in their preferred languages and timezone representations.&lt;/p&gt;

&lt;p&gt;Read the full blog post on the &lt;a href="https://www.syncfusion.com/blogs/post/aspnet-core-scheduler-features" rel="noopener noreferrer"&gt;Syncfusion Website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aspnetcore</category>
      <category>eventcalendar</category>
      <category>eventscheduling</category>
      <category>scheduler</category>
    </item>
    <item>
      <title>Still Exporting CSV Files? Embed a Spreadsheet Editor in Your Web App Instead</title>
      <dc:creator>Lucy Muturi</dc:creator>
      <pubDate>Fri, 24 Jul 2026 11:28:18 +0000</pubDate>
      <link>https://dev.to/syncfusion/still-exporting-csv-files-embed-a-spreadsheet-editor-in-your-web-app-instead-5fbk</link>
      <guid>https://dev.to/syncfusion/still-exporting-csv-files-embed-a-spreadsheet-editor-in-your-web-app-instead-5fbk</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; CSV exports slow down modern web apps with version issues, stale data, and broken validation. In-browser spreadsheets offer a more efficient approach by enabling structured, real-time editing directly inside applications, improving data consistency, user experience, and workflow efficiency across dashboards, operations, and internal tools.&lt;/p&gt;

&lt;p&gt;If your app still relies on “Export to CSV” for quick edits, you’ve probably seen this happen:&lt;/p&gt;

&lt;p&gt;Someone downloads a file, opens it in Excel or Google Sheets, makes a few updates… and then things start getting messy.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which version is the latest?&lt;/li&gt;
&lt;li&gt;Why did the upload fail?&lt;/li&gt;
&lt;li&gt;Who changed this value?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first, it feels like a simple workflow. But once teams depend on it daily, the cracks start to show.&lt;/p&gt;

&lt;p&gt;A modern alternative is an in-browser spreadsheet: an Excel-like editor embedded directly in your web app. Users edit data in place with familiar spreadsheet interactions without leaving the product.&lt;/p&gt;

&lt;p&gt;In this article, we’ll look at how to embed an &lt;strong&gt;in-browser spreadsheet&lt;/strong&gt; in React using Syncfusion&lt;sup&gt;®&lt;/sup&gt; &lt;a href="https://www.syncfusion.com/spreadsheet-editor-sdk/react-spreadsheet-editor" rel="noopener noreferrer"&gt;React Spreadsheet Editor&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hidden problem with CSV exports
&lt;/h2&gt;

&lt;p&gt;CSV exports weren’t designed for continuous, in-app data editing. They were a workaround useful at a time when web apps couldn’t handle complex grids.&lt;/p&gt;

&lt;p&gt;Today, that workaround creates more problems than it solves.&lt;/p&gt;

&lt;p&gt;Here’s what typically goes wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Version confusion:&lt;/strong&gt; Multiple files floating around, no clear “source of truth”.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stale data:&lt;/strong&gt; The moment a file is exported, it starts drifting away from live data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broken structure:&lt;/strong&gt; No formulas, no formatting, no validation, just raw values.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extra engineering overhead:&lt;/strong&gt; Imports fail, formats mismatch, edge cases pile up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Individually, these are small issues. Together, they slow teams down and introduce unnecessary risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the export breaks, productivity follows
&lt;/h2&gt;

&lt;p&gt;What looks like a simple loop export, edit, and upload quietly adds friction at every step.&lt;/p&gt;

&lt;p&gt;Now imagine a finance team updating quarterly forecasts.&lt;/p&gt;

&lt;p&gt;They export a CSV, tweak some numbers, and re-upload it. But formulas are gone, number formats are inconsistent, and validation rules don’t exist anymore.&lt;/p&gt;

&lt;p&gt;Someone spots an error. Another file is downloaded. Another version is created.&lt;/p&gt;

&lt;p&gt;By the time data is “final,” nobody fully trusts it.&lt;/p&gt;

&lt;p&gt;This isn’t a tooling issue; it’s a workflow problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what’s changing?
&lt;/h2&gt;

&lt;p&gt;Instead of pushing users out to Excel, many modern web apps are doing the opposite:&lt;/p&gt;

&lt;p&gt;They’re bringing spreadsheet-like editing directly into the application.&lt;/p&gt;

&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edit data in place&lt;/li&gt;
&lt;li&gt;Keep everything connected to live data&lt;/li&gt;
&lt;li&gt;Apply validation before errors happen&lt;/li&gt;
&lt;li&gt;Maintain a single source of truth&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No exports. No uploads. No guesswork.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSV exports vs. in-browser Spreadsheets: What actually changes
&lt;/h2&gt;

&lt;p&gt;Here’s the real difference, not in features, but in experience:&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;&amp;nbsp;CSV Workflow&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&amp;nbsp;In-Browser Spreadsheet&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;Download → Edit → Upload&lt;/td&gt;
&lt;td&gt;&amp;nbsp;Edit instantly inside the app.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;Static snapshot of data&lt;/td&gt;
&lt;td&gt;&amp;nbsp;Always working with live data.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;No built-in validation&lt;/td&gt;
&lt;td&gt;&amp;nbsp;Controlled, rule-based editing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;Multiple file versions&lt;/td&gt;
&lt;td&gt;&amp;nbsp;One shared source of truth.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;Error-prone updates&lt;/td&gt;
&lt;td&gt;&amp;nbsp;Guided, structured changes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The shift isn’t just technical; it’s about removing unnecessary steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  When CSV still makes sense
&lt;/h2&gt;

&lt;p&gt;CSV exports still have their place.&lt;/p&gt;

&lt;p&gt;They’re useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data needs to be shared externally&lt;/li&gt;
&lt;li&gt;Offline access is required&lt;/li&gt;
&lt;li&gt;The task involves one-time exports&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The problem arises when CSV becomes the default for everyday editing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes an in-browser Spreadsheet enterprise-ready?
&lt;/h2&gt;

&lt;p&gt;Embedding a spreadsheet into a production application requires more than just rendering a grid.&lt;/p&gt;

&lt;p&gt;Key considerations include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance:&lt;/strong&gt; Large datasets need efficient rendering (virtualization) and a careful recalculation strategy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability:&lt;/strong&gt; Define how edits sync to your backend (save-on-change vs save-on-submit, conflict handling).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintainability:&lt;/strong&gt; Prefer a component with stable APIs and documented configuration patterns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security/permissions:&lt;/strong&gt; Restrict editing by role, protecting sheets/ranges, and validating inputs at the cell level.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility:&lt;/strong&gt; Keyboard navigation and screen reader support matter for enterprise rollouts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The modern approach: In-browser Spreadsheet Editor
&lt;/h2&gt;

&lt;p&gt;An embedded spreadsheet component brings spreadsheet-style editing directly into your web app, without forcing users to switch tools.&lt;/p&gt;

&lt;p&gt;Instead of exporting files and re-importing them later, users can work with data in a structured, interactive grid that stays connected to your application.&lt;/p&gt;

&lt;p&gt;This approach allows your app to stay in control of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data access and permissions&lt;/li&gt;
&lt;li&gt;Validation and business rules&lt;/li&gt;
&lt;li&gt;Real-time updates and consistency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Today, many teams use ready-made spreadsheet components to support this pattern, rather than building everything from scratch.&lt;/p&gt;

&lt;p&gt;For example, in a React application, a component like the Syncfusion React Spreadsheet Editor can provide the core functionality needed to support in-app editing, including handling large datasets, applying validation, and maintaining a consistent data structure.&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%2F07%2FAdvanced-data-management-features-in-React-Spreadsheet.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%2F07%2FAdvanced-data-management-features-in-React-Spreadsheet.png" alt="Advanced data management features in React Spreadsheet" width="799" height="352"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Advanced data management features in React Spreadsheet
  &lt;p&gt;&lt;/p&gt;

&lt;p&gt;Read the full blog post on the &lt;a href="https://www.syncfusion.com/blogs/post/in-browser-spreadsheet-vs-csv-export" rel="noopener noreferrer"&gt;Syncfusion Website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>datagrid</category>
      <category>spreadsheeteditor</category>
      <category>webapplicationux</category>
    </item>
    <item>
      <title>Best JavaScript Data Grid Libraries: Which One Is Right for Your App?</title>
      <dc:creator>Lucy Muturi</dc:creator>
      <pubDate>Fri, 24 Jul 2026 06:02:37 +0000</pubDate>
      <link>https://dev.to/syncfusion/best-javascript-data-grid-libraries-which-one-is-right-for-your-app-4caj</link>
      <guid>https://dev.to/syncfusion/best-javascript-data-grid-libraries-which-one-is-right-for-your-app-4caj</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Choosing a JavaScript data grid library can be challenging, especially when modern applications require features such as editing, filtering, export, accessibility, and high-performance data handling. This comparison reviews AG Grid, TanStack Table, Syncfusion JavaScript DataGrid, Handsontable, and Kendo UI Grid to help developers identify the best fit for their application requirements.&lt;/p&gt;

&lt;p&gt;At first glance, displaying data in a web application seems simple. Render a table, load some rows, and you’re done.&lt;/p&gt;

&lt;p&gt;But that simplicity rarely survives contact with real-world requirements.&lt;/p&gt;

&lt;p&gt;Users eventually ask for filtering, inline editing, exports, grouped views, responsive layouts, role-based access, keyboard navigation, localization, and the ability to handle &lt;strong&gt;millions of records&lt;/strong&gt; through virtualization, paging, incremental loading, and server-side data operations.&lt;/p&gt;

&lt;p&gt;That’s why choosing a JavaScript data grid isn’t just a UI decision. The right grid can accelerate development and improve user productivity. The wrong one can create performance issues, increase maintenance costs, and slow down future product development.&lt;/p&gt;

&lt;p&gt;In this guide, we’ll compare five popular JavaScript data grid libraries in 2026:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AG Grid&lt;/li&gt;
&lt;li&gt;TanStack Table&lt;/li&gt;
&lt;li&gt;Syncfusion JavaScript DataGrid&lt;/li&gt;
&lt;li&gt;Handsontable&lt;/li&gt;
&lt;li&gt;Kendo UI Grid&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rather than looking for a universal winner, we’ll focus on which grid works best for specific application requirements.&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;Feature&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AG Grid&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;TanStack&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Syncfusion&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Handsontable&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Kendo&lt;strong&gt; &lt;/strong&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Virtualization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;API-driven&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Excel Export&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Custom&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PDF Export&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Custom&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Built-in Editing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Custom&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Headless&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How we evaluated these JavaScript Data Grids
&lt;/h2&gt;

&lt;p&gt;This comparison is based on publicly available product documentation and capabilities reviewed in July 2026. We evaluated each library based on its data-handling model, built-in features, customization options, developer experience, accessibility support, licensing approach, ecosystem maturity, and suitability for common application scenarios. &lt;/p&gt;

&lt;p&gt;The order does not represent a universal ranking. Each grid has different strengths, and the best choice depends on your application’s workflows, technical requirements, framework, budget, and long-term maintenance needs. Product capabilities and licensing terms can change, so verify the latest vendor documentation before making a final decision. &lt;/p&gt;

&lt;p&gt;Feature availability, APIs, licensing, and accessibility details may also differ across framework-specific editions. Verify the documentation for the exact package and edition your application uses. &lt;/p&gt;

&lt;h2&gt;
  
  
  Why choosing the right JavaScript Data Grid matters
&lt;/h2&gt;

&lt;p&gt;In many business applications, the data grid becomes the primary workspace for users. Instead of simply viewing data, users filter records, edit values, export reports, review exceptions, and complete day-to-day operational tasks directly within the grid.&lt;/p&gt;

&lt;p&gt;This is common in applications such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Admin dashboards&lt;/li&gt;
&lt;li&gt;ERP and CRM systems&lt;/li&gt;
&lt;li&gt;Inventory management software&lt;/li&gt;
&lt;li&gt;Financial reporting tools&lt;/li&gt;
&lt;li&gt;Analytics platforms&lt;/li&gt;
&lt;li&gt;Data review and approval workflows&lt;/li&gt;
&lt;li&gt;Internal operations portals&lt;/li&gt;
&lt;li&gt;B2B SaaS applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The challenge is that not all JavaScript data grid libraries are designed for the same purpose.&lt;/p&gt;

&lt;p&gt;Some provide a fully featured component with built-in capabilities such as editing, filtering, grouping, and export. Others focus on table logic and give developers complete control over the user interface. There are also solutions designed specifically for spreadsheet-style workflows and data-entry scenarios.&lt;/p&gt;

&lt;p&gt;Because the grid often becomes one of the most frequently used parts of an application, choosing the right solution can affect development effort, performance, maintainability, and overall user experience. Before comparing individual libraries, it’s worth understanding the different approaches available and how they align with your application’s requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three approaches to JavaScript Data Grids
&lt;/h2&gt;

&lt;p&gt;Before comparing products, it’s useful to understand the three major categories of grid solutions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component-based grids
&lt;/h3&gt;

&lt;p&gt;Component-based grids ship with built-in UI, interaction models, styling systems, and common data operations.&lt;/p&gt;

&lt;p&gt;They’re typically chosen by teams that want enterprise-grade functionality without having to build every interaction from scratch.&lt;/p&gt;

&lt;p&gt;Common examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AG Grid&lt;/li&gt;
&lt;li&gt;Syncfusion DataGrid&lt;/li&gt;
&lt;li&gt;Kendo UI Grid&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These solutions work particularly well for business applications, reporting portals, ERP systems, CRM platforms, and operational dashboards.&lt;/p&gt;

&lt;h3&gt;
  
  
  Headless grid libraries
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Headless libraries focus on data-processing logic rather than visual presentation.&lt;/li&gt;
&lt;li&gt;Instead of providing a complete UI, they offer APIs and state management that let you build your own experience.&lt;/li&gt;
&lt;li&gt;TanStack Table is a widely used example of this approach.&lt;/li&gt;
&lt;li&gt;This model works well for organizations with established design systems and teams that require complete UI control.&lt;/li&gt;
&lt;li&gt;In return for that control, the development team is responsible for implementing or integrating the rendered UI, styling, semantic markup, accessibility, focus management, and keyboard interaction behavior required by the application.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Spreadsheet-oriented grids
&lt;/h3&gt;

&lt;p&gt;Some applications revolve around data entry rather than data presentation.&lt;/p&gt;

&lt;p&gt;Spreadsheet-style grids provide cell editing, keyboard workflows, copy-paste support, validation, and interactions that mimic spreadsheet software.&lt;/p&gt;

&lt;p&gt;Handsontable is a popular candidate in this category.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to evaluate a JavaScript data grid library
&lt;/h2&gt;

&lt;p&gt;When comparing grid libraries, feature count alone is rarely the deciding factor for long-term success. Most mature products already support filtering, sorting, paging, and editing. &lt;/p&gt;

&lt;p&gt;The more important question is whether the available features match your workflows, performance requirements, customization needs, and maintenance capacity. &lt;/p&gt;

&lt;p&gt;Instead, focus on these questions:&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;How will the grid behave with realistic datasets?&lt;/p&gt;

&lt;p&gt;Consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large record counts&lt;/li&gt;
&lt;li&gt;Frequent updates&lt;/li&gt;
&lt;li&gt;Virtual scrolling&lt;/li&gt;
&lt;li&gt;Server-side data operations&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Editing requirements
&lt;/h3&gt;

&lt;p&gt;Do users need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inline editing?&lt;/li&gt;
&lt;li&gt;Batch updates?&lt;/li&gt;
&lt;li&gt;Validation rules?&lt;/li&gt;
&lt;li&gt;Custom editors?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Customization
&lt;/h3&gt;

&lt;p&gt;How closely must the grid match your design system?&lt;/p&gt;

&lt;p&gt;Some products provide extensive customization, while others prioritize ready-made functionality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessibility
&lt;/h3&gt;

&lt;p&gt;For many enterprise applications, accessibility is a requirement rather than an option. Verify the grid against your organization’s required WCAG 2.1 or WCAG 2.2 conformance level, and test the configured implementation rather than relying only on a vendor-level accessibility statement. &lt;/p&gt;

&lt;p&gt;Evaluate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keyboard-only navigation and operation &lt;/li&gt;
&lt;li&gt;Logical and visible focus management &lt;/li&gt;
&lt;li&gt;Screen-reader behavior &lt;/li&gt;
&lt;li&gt;Accessible editing, validation, and error reporting&lt;/li&gt;
&lt;li&gt;Roles, names, states, and relationships &lt;/li&gt;
&lt;li&gt;Alternatives for drag-based interactions &lt;/li&gt;
&lt;li&gt;Behavior after customization and theming &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Export and reporting
&lt;/h3&gt;

&lt;p&gt;Many business workflows still depend on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Excel export&lt;/li&gt;
&lt;li&gt;CSV export&lt;/li&gt;
&lt;li&gt;PDF export&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If reporting is critical, ensure these capabilities meet your requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Licensing and support
&lt;/h3&gt;

&lt;p&gt;Before committing, verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Commercial licensing terms&lt;/li&gt;
&lt;li&gt;Production restrictions&lt;/li&gt;
&lt;li&gt;Support availability&lt;/li&gt;
&lt;li&gt;Upgrade policies&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  JavaScript Data Grid libraries at a glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table width="623"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Library&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Primary Strength&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AG Grid&lt;/td&gt;
&lt;td&gt;Data-intensive enterprise applications&lt;/td&gt;
&lt;td&gt;Extensive feature set and scalability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TanStack Table&lt;/td&gt;
&lt;td&gt;Design-system-driven products&lt;/td&gt;
&lt;td&gt;Complete UI flexibility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Syncfusion DataGrid&lt;/td&gt;
&lt;td&gt;Business applications and dashboards&lt;/td&gt;
&lt;td&gt;Broad enterprise functionality out of the box&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Handsontable&lt;/td&gt;
&lt;td&gt;Spreadsheet-style workflows&lt;/td&gt;
&lt;td&gt;Familiar editing experience&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kendo UI Grid&lt;/td&gt;
&lt;td&gt;Existing Telerik ecosystems&lt;/td&gt;
&lt;td&gt;Integration with a larger UI platform&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Detailed review of the top JavaScript Data Grid libraries
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. AG Grid
&lt;/h3&gt;

&lt;p&gt;AG Grid is widely adopted in enterprise web applications and is frequently evaluated for data-intensive use cases. Its extensive feature set, multiple row models, and support for popular JavaScript frameworks make it a strong candidate for applications with complex data requirements. &lt;/p&gt;

&lt;p&gt;One of AG Grid’s biggest strengths is its ability to handle complex requirements without relying heavily on additional libraries. Features such as filtering, grouping, aggregation, pivoting, virtualization, and advanced data operations make it a strong candidate for large-scale business applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key strengths
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Extensive feature set for enterprise scenarios&lt;/li&gt;
&lt;li&gt;Multiple row models for client-side and server-side data scenarios&lt;/li&gt;
&lt;li&gt;Mature ecosystem and documentation&lt;/li&gt;
&lt;li&gt;Community and Enterprise editions to suit different project needs&lt;/li&gt;
&lt;li&gt;Works across multiple JavaScript frameworks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Things to consider
&lt;/h3&gt;

&lt;p&gt;AG Grid’s breadth of functionality can be more than smaller projects require. Teams should also carefully review feature availability between the Community and Enterprise editions before making a long-term commitment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ideal use cases
&lt;/h3&gt;

&lt;p&gt;AG Grid is particularly well suited for reporting systems, operational dashboards, financial applications, analytics platforms, and enterprise software where users spend significant time working with data.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. TanStack Table
&lt;/h3&gt;

&lt;p&gt;Unlike traditional grid components, TanStack Table takes a headless approach. Instead of providing a ready-made user interface, it focuses on the underlying table logic and state management while giving developers complete control over rendering and styling.&lt;/p&gt;

&lt;p&gt;This flexibility makes it suitable for teams that maintain their own design systems or need highly customized user experiences. Rather than adapting a prebuilt grid to match an application’s design, developers can build exactly the experience they need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key strengths
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Complete control over UI and styling&lt;/li&gt;
&lt;li&gt;Headless architecture with minimal visual constraints&lt;/li&gt;
&lt;li&gt;Well suited for integration with custom design systems&lt;/li&gt;
&lt;li&gt;Supports multiple frontend frameworks&lt;/li&gt;
&lt;li&gt;Composable row models and controlled state management&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Things to consider
&lt;/h3&gt;

&lt;p&gt;This flexibility comes with additional implementation responsibility. TanStack Table provides the underlying table logic rather than a complete grid interface, so developers must implement or integrate the UI rendering, styling, semantic markup, accessibility, focus management, and keyboard interactions required by their application. Features available out of the box in component-based grids may therefore require additional development, integration, and testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ideal use cases
&lt;/h3&gt;

&lt;p&gt;TanStack Table is a strong choice for SaaS applications, internal platforms, design-system-driven products, and teams that prioritize flexibility over out-of-the-box functionality.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Syncfusion JavaScript DataGrid
&lt;/h3&gt;

&lt;p&gt;Syncfusion &lt;a href="https://www.syncfusion.com/javascript-ui-controls/js-data-grid" rel="noopener noreferrer"&gt;JavaScript DataGrid&lt;/a&gt; is a feature-rich HTML5 data grid component for displaying and managing tabular data in JavaScript applications. It includes data binding, editing, Excel-like filtering, custom sorting, aggregation, selection, and export support for Excel, CSV, and PDF formats.&lt;/p&gt;

&lt;p&gt;It is designed for applications where the grid supports real business workflows, not only data display. Teams can bind data from local and remote data sources, including JavaScript object arrays, JSON, OData services, REST APIs, and other supported endpoints through DataManager.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key strengths
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Broad built-in functionality for data presentation and editing &lt;/li&gt;
&lt;li&gt;Local and remote data binding through DataManager &lt;/li&gt;
&lt;li&gt;Filtering, grouping, sorting, summaries, and selection &lt;/li&gt;
&lt;li&gt;Export options for Excel, CSV, and PDF.&lt;/li&gt;
&lt;li&gt;Responsive layouts, themes, and localization support &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Things to consider
&lt;/h3&gt;

&lt;p&gt;Applications that require complete control over markup and interaction behavior may prefer a headless solution. Teams should also evaluate licensing, package size, required modules, framework compatibility, and whether the broader component suite aligns with their project needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ideal use cases
&lt;/h3&gt;

&lt;p&gt;Syncfusion JavaScript DataGrid works well for ERP modules, CRM systems, inventory management applications, business dashboards, reporting portals, and enterprise applications with complex data workflows.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Handsontable
&lt;/h3&gt;

&lt;p&gt;Handsontable approaches data grids from a different angle. Rather than focusing primarily on data presentation, it emphasizes spreadsheet-style interaction and editing experiences.&lt;/p&gt;

&lt;p&gt;Users can work directly with cells, making it a natural fit for workflows where entering, validating, and manipulating data is more important than simply viewing it.&lt;/p&gt;

&lt;p&gt;Organizations migrating spreadsheet-based processes to web applications often find Handsontable particularly appealing because it provides familiar interaction patterns that reduce the learning curve for end users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key strengths
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Spreadsheet-like user experience&lt;/li&gt;
&lt;li&gt;Cell-based editing workflows&lt;/li&gt;
&lt;li&gt;Familiar copy-and-paste interactions&lt;/li&gt;
&lt;li&gt;Validation and structured data-entry capabilities&lt;/li&gt;
&lt;li&gt;Framework support across modern JavaScript ecosystems&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Things to consider
&lt;/h3&gt;

&lt;p&gt;Not every application benefits from spreadsheet-style behavior. If users primarily view data rather than actively edit and manipulate it, a traditional data grid may be a better fit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ideal use cases
&lt;/h3&gt;

&lt;p&gt;Handsontable is well suited for planning tools, budgeting systems, resource management applications, inventory workflows, financial data-entry screens, and other spreadsheet-oriented business processes.&lt;/p&gt;

&lt;p&gt;Read the full blog post on the &lt;a href="https://www.syncfusion.com/blogs/post/best-javascript-data-grid-libraries" rel="noopener noreferrer"&gt;Syncfusion Website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>datagrid</category>
      <category>frontend</category>
      <category>uicomponents</category>
    </item>
    <item>
      <title>Why Your Browser Freezes with Large Excel Files in JavaScript Spreadsheet Apps and How to Fix It</title>
      <dc:creator>Lucy Muturi</dc:creator>
      <pubDate>Wed, 22 Jul 2026 09:57:13 +0000</pubDate>
      <link>https://dev.to/syncfusion/why-your-browser-freezes-with-large-excel-files-in-javascript-spreadsheet-apps-and-how-to-fix-it-3j65</link>
      <guid>https://dev.to/syncfusion/why-your-browser-freezes-with-large-excel-files-in-javascript-spreadsheet-apps-and-how-to-fix-it-3j65</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Browser freezes with large Excel files are usually caused by inefficient rendering, not data size. This blog explores how modern spreadsheet architectures handle large datasets using virtualization and optimized processing to deliver smooth performance in web applications.&lt;/p&gt;

&lt;p&gt;Your browser freezes.&lt;br&gt;
Scrolling lags.&lt;br&gt;
Even editing a single cell feels slow.&lt;/p&gt;

&lt;p&gt;If you’ve ever tried opening a large Excel file, say 50K, 100K, or more rows, in a web app, you’ve probably hit this wall. And it’s frustrating, because the data itself isn’t the real problem.&lt;/p&gt;

&lt;p&gt;The truth is, most spreadsheet performance issues in the browser come down to how the data is handled, not how much of it exists.&lt;/p&gt;

&lt;p&gt;Let’s break that down and look at how the Syncfusion&lt;sup&gt;®&lt;/sup&gt; &lt;a href="https://www.syncfusion.com/spreadsheet-editor-sdk/javascript-spreadsheet-editor" rel="noopener noreferrer"&gt;JavaScript Spreadsheet&lt;/a&gt; component handles this at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  It’s not the data. It’s the way it’s rendered.
&lt;/h2&gt;

&lt;p&gt;It’s easy to assume that your dataset is just “too big.” But modern browsers can handle large datasets just fine as long as you don’t try to do everything at once.&lt;/p&gt;

&lt;p&gt;What usually goes wrong?&lt;/p&gt;

&lt;p&gt;When a spreadsheet loads a large dataset in the naive way, it tries to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Render every cell into the DOM&lt;/li&gt;
&lt;li&gt;Keep all rows active in memory&lt;/li&gt;
&lt;li&gt;Recalculate formulas immediately&lt;/li&gt;
&lt;li&gt;Repaint the layout on every interaction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Individually, these are fine. Together, they overwhelm the browser’s single thread.&lt;/p&gt;

&lt;p&gt;And that’s when things start to freeze.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the slowdown really comes from
&lt;/h2&gt;

&lt;p&gt;If you zoom into what’s happening behind the scenes, a few patterns show up consistently.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Too many DOM elements:&lt;/strong&gt; Rendering thousands of rows means creating thousands (or hundreds of thousands) of DOM nodes. That’s expensive, not just to create, but also to maintain as the UI updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layout recalculations:&lt;/strong&gt; Scrolling or editing forces the browser to constantly reflow and repaint the UI. With a large grid, even small changes cascade into noticeable lag.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blocking operations:&lt;/strong&gt; Large file parsing or synchronous calculations can block the main thread. While that work is happening, your UI has no chance to respond.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory pressure:&lt;/strong&gt; Keeping everything loaded values, styles, formulas adds up quickly. As memory usage climbs, responsiveness drops.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is unusual. It’s just what happens when the browser is asked to do too much, all at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  A smarter way to handle large spreadsheets
&lt;/h2&gt;

&lt;p&gt;The key shift is simple:&lt;/p&gt;

&lt;p&gt;Don’t render everything; only render what the user can see.&lt;/p&gt;

&lt;p&gt;This is where virtual rendering (often called virtual scrolling) changes everything.&lt;/p&gt;

&lt;p&gt;Instead of loading an entire dataset into the DOM, you render just a small window of it, the visible rows and columns. As the user scrolls, the UI updates dynamically, swapping in the next set of data.&lt;/p&gt;

&lt;p&gt;In practice, that means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The DOM stays small and manageable&lt;/li&gt;
&lt;li&gt;Scrolling remains smooth&lt;/li&gt;
&lt;li&gt;The browser isn’t overwhelmed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simple idea, but it has a huge impact.&lt;/p&gt;

&lt;p&gt;Virtual scrolling is the most impactful technique for handling large spreadsheets in the browser, and it only works if the spreadsheet engine is built to support it at the architecture level.&lt;/p&gt;

&lt;h2&gt;
  
  
  From theory to practice: How Syncfusion handles it
&lt;/h2&gt;

&lt;p&gt;This is exactly where a solution like Syncfusion &lt;a href="https://www.syncfusion.com/spreadsheet-editor-sdk/javascript-spreadsheet-editor" rel="noopener noreferrer"&gt;JavaScript Spreadsheet&lt;/a&gt; makes a difference.&lt;/p&gt;

&lt;p&gt;Instead of requiring you to build complex performance optimizations from scratch, it handles them internally, keeping your application responsive even with large datasets.&lt;/p&gt;

&lt;p&gt;It’s designed to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Render only what’s necessary at any given moment&lt;/li&gt;
&lt;li&gt;Process large files progressively instead of all at once&lt;/li&gt;
&lt;li&gt;Recalculate formulas efficiently without blocking interactions&lt;/li&gt;
&lt;li&gt;Manage memory in a way that scales with your data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is a spreadsheet experience that remains smooth, even when working with tens of thousands of rows.&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%2F07%2FHandling-Large-Datasets-in-JavaScript-Spreadsheet-Editor.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%2F07%2FHandling-Large-Datasets-in-JavaScript-Spreadsheet-Editor.png" alt="Handling Large Datasets in JavaScript Spreadsheet Editor" width="800" height="507"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Large Datasets Rendering in JavaScript Spreadsheet Editor
  &lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance techniques in Syncfusion JavaScript Spreadsheet
&lt;/h2&gt;

&lt;p&gt;Syncfusion applies several built-in optimizations across rendering, data processing, formula calculation, and memory management.&lt;/p&gt;

&lt;p&gt;Here’s how each one contributes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rendering optimizations&lt;/strong&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://help.syncfusion.com/document-processing/excel/spreadsheet/javascript-es5/performance-best-practices#virtual-scrolling" rel="noopener noreferrer"&gt;Virtual scrolling&lt;/a&gt; renders only the visible cells, reducing DOM size and preventing scroll lag or Excel freeze.&lt;/li&gt;
&lt;li&gt;A lightweight DOM structure with optimized re‑render cycles helps maintain smooth spreadsheet performance during editing and navigation.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data processing&lt;/strong&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://help.syncfusion.com/document-processing/excel/spreadsheet/javascript-es5/performance-best-practices#chunk-response-processing" rel="noopener noreferrer"&gt;Chunk response processing&lt;/a&gt; loads large Excel files in smaller parts instead of a single heavy response, keeping the UI responsive and avoiding “large spreadsheet not responding” errors.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://help.syncfusion.com/document-processing/excel/spreadsheet/javascript-es5/performance-best-practices#configure-json-serialization-options-during-open" rel="noopener noreferrer"&gt;Optimized JSON serialization&lt;/a&gt; excludes unnecessary styles and objects to reduce payload size and improve file open speed.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://help.syncfusion.com/document-processing/excel/spreadsheet/javascript-es5/performance-best-practices#configuring-threshold-limits" rel="noopener noreferrer"&gt;Threshold limits&lt;/a&gt; prevent very large files from causing timeouts by capping the maximum data and file size.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://help.syncfusion.com/document-processing/excel/spreadsheet/javascript-es5/performance-best-practices#optimize-excel-open-with-parsing-options" rel="noopener noreferrer"&gt;Parsing options&lt;/a&gt; like &lt;strong&gt;&lt;code&gt;IgnoreStyle&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;IgnoreFormat&lt;/code&gt;&lt;/strong&gt; skip unnecessary styles to speed up large Excel imports.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Formula engine&lt;/strong&gt;

&lt;ol&gt;
&lt;li&gt;An efficient formula engine recalculates only affected cells instead of the entire worksheet.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://help.syncfusion.com/document-processing/excel/spreadsheet/javascript-es5/performance-best-practices#manual-calculation-mode" rel="noopener noreferrer"&gt;Manual calculation mode&lt;/a&gt; allows developers to delay formula updates during bulk operations, preventing UI freezes.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Save performance:&lt;/strong&gt; 

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://help.syncfusion.com/document-processing/excel/spreadsheet/javascript-es5/performance-best-practices#handling-large-file-saves-with-isfullpost-option" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;isFullPost&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;&lt;code&gt;= false&lt;/code&gt;&lt;/strong&gt; option optimizes save operations for large files, bypassing heavy form submission, preventing save timeouts and delays.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory management&lt;/strong&gt;

&lt;ol&gt;
&lt;li&gt;Efficient internal storage keeps memory usage low even with large datasets.&lt;/li&gt;
&lt;li&gt;Disabling &lt;a href="https://help.syncfusion.com/document-processing/excel/spreadsheet/javascript-es5/performance-best-practices#disabling-aggregate-calculation" rel="noopener noreferrer"&gt;aggregate calculations&lt;/a&gt; improves selection performance on large ranges.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read the full blog post on the &lt;a href="https://www.syncfusion.com/blogs/post/excel-freeze-browser-large-dataset-performance" rel="noopener noreferrer"&gt;Syncfusion Website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>excellikespreadsheet</category>
      <category>spreadsheet</category>
      <category>spreadsheetcomponent</category>
    </item>
    <item>
      <title>What’s New in Blazor 2026 Volume 2: AI, Analytics, and Productivity Enhancements</title>
      <dc:creator>Lucy Muturi</dc:creator>
      <pubDate>Tue, 21 Jul 2026 10:42:02 +0000</pubDate>
      <link>https://dev.to/syncfusion/whats-new-in-blazor-2026-volume-2-ai-analytics-and-productivity-enhancements-3nnk</link>
      <guid>https://dev.to/syncfusion/whats-new-in-blazor-2026-volume-2-ai-analytics-and-productivity-enhancements-3nnk</guid>
      <description>&lt;p&gt;&lt;strong&gt;TLDR:&lt;/strong&gt; From AI-assisted editing and voice-enabled interactions to smarter analytics, project planning, and content authoring, Syncfusion Blazor 2026 Volume 2 introduces a range of developer-focused enhancements across its most-used components. Read the full blog to discover what’s new, see where these features fit into real applications, and learn how to get started.&lt;/p&gt;

&lt;p&gt;A few years ago, building a Blazor application mostly meant assembling UI components and connecting APIs. Today, developers are expected to integrate AI experiences, analyze growing datasets, support richer content creation, and deliver all of it without sacrificing performance or usability.&lt;/p&gt;

&lt;p&gt;That’s where many development teams spend their time—not building screens but solving the practical challenges behind them.&lt;/p&gt;

&lt;p&gt;Syncfusion&lt;sup&gt;®&lt;/sup&gt; &lt;a href="https://www.syncfusion.com/blazor-components" rel="noopener noreferrer"&gt;Blazor&lt;/a&gt; 2026 Volume 2 focuses on those challenges, introducing AI-assisted editing, smarter analytics capabilities, productivity improvements, and a new SDK packaging model that helps teams adopt only the components they need.&lt;/p&gt;

&lt;p&gt;Before exploring the component updates, let’s take a quick look at this new packaging approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pick the right SDK for your project
&lt;/h2&gt;

&lt;p&gt;Not every application requires a full UI suite. A reporting platform may depend heavily on grids and charts, while a project management application might only need scheduling and planning components.&lt;/p&gt;

&lt;p&gt;With the &lt;a href="https://www.syncfusion.com/products/whatsnew/blazor-components" rel="noopener noreferrer"&gt;2026 Volume 2&lt;/a&gt; release, Syncfusion offers seven &lt;strong&gt;Standalone UI SDKs&lt;/strong&gt;, each focused on a specific development area:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/grid-sdk" rel="noopener noreferrer"&gt;Grid SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/chart-sdk" rel="noopener noreferrer"&gt;Chart SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/scheduler-sdk" rel="noopener noreferrer"&gt;Scheduler SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/gantt-sdk" rel="noopener noreferrer"&gt;Gantt SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/rich-text-editor-sdk" rel="noopener noreferrer"&gt;Rich Text Editor SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/diagram-sdk" rel="noopener noreferrer"&gt;Diagram SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.syncfusion.com/file-manager-sdk" rel="noopener noreferrer"&gt;File Manager SDK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This model allows teams to adopt only the components relevant to their applications instead of starting with a broader collection of controls.&lt;/p&gt;

&lt;p&gt;For projects spanning multiple functional areas, the &lt;strong&gt;UI Component Suite&lt;/strong&gt; remains available. It includes the &lt;strong&gt;Grid SDK&lt;/strong&gt;, &lt;strong&gt;Chart SDK&lt;/strong&gt;, and &lt;strong&gt;File Manager SDK&lt;/strong&gt;, with the &lt;strong&gt;Gantt&lt;/strong&gt;, &lt;strong&gt;Scheduler&lt;/strong&gt;, &lt;strong&gt;Diagram&lt;/strong&gt;, and &lt;strong&gt;Rich Text Editor&lt;/strong&gt; SDKs available separately.&lt;/p&gt;

&lt;p&gt;Existing customers don’t need to make any licensing changes. Current entitlements remain unchanged, and all new Volume 2 features are available within existing license coverage. The Standalone UI SDK model only affects how new purchases are packaged going forward.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; To learn more, see the &lt;a href="https://www.syncfusion.com/blogs/post/syncfusion-standalone-ui-sdks" rel="noopener noreferrer"&gt;Standalone UI SDKs announcement&lt;/a&gt; and the &lt;a href="https://www.syncfusion.com/blogs/post/syncfusion-essential-studio-2026-vol-2" rel="noopener noreferrer"&gt;Essential Studio 2026 Volume 2 release&lt;/a&gt; blogs.&lt;/p&gt;

&lt;h2&gt;
  
  
  New Inline AI Assist: Bring AI into the editing experience
&lt;/h2&gt;

&lt;p&gt;Many AI integrations still rely on separate chat panels, forcing users to switch between their content and the AI conversation. In content-heavy applications, that extra context switching can quickly disrupt productivity.&lt;/p&gt;

&lt;p&gt;To address this, we introduce the &lt;a href="https://www.syncfusion.com/blazor-components/blazor-inline-ai-assist" rel="noopener noreferrer"&gt;Inline AI Assist&lt;/a&gt;, a new component that brings AI interactions directly into the editing surface. Users can select content, request changes, review responses, and apply updates without leaving their current context.&lt;/p&gt;

&lt;p&gt;For example, in a Rich Text Editor, a user can highlight a paragraph, ask AI to simplify or rewrite it, and review the streamed suggestion immediately. The same experience fits naturally into IDEs, form-driven applications, and knowledge management tools.&lt;/p&gt;

&lt;p&gt;The Blazor Inline AI Assist supports two interaction modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inline mode:&lt;/strong&gt; Displays AI suggestions next to the selected content, making it ideal for rewriting text, expanding summaries, or generating code without interrupting the editing process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pop-up mode:&lt;/strong&gt; Provides a more conversational experience when users need broader assistance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Inline and pop-up response modes.&lt;/li&gt;
&lt;li&gt;Command actions with mention-style suggestions.&lt;/li&gt;
&lt;li&gt;Accept, discard, and custom response actions.&lt;/li&gt;
&lt;li&gt;Configurable action toolbar.&lt;/li&gt;
&lt;li&gt;Automatic Markdown-to-HTML rendering.&lt;/li&gt;
&lt;li&gt;Streaming responses with stop controls.&lt;/li&gt;
&lt;li&gt;Visual indicators for thinking and editing states.&lt;/li&gt;
&lt;li&gt;Customizable appearance.&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%2F07%2FInline-AI-Assist-for-Blazor.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%2F07%2FInline-AI-Assist-for-Blazor.gif" alt="Inline AI Assist for Blazor" width="768" height="636"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Inline AI Assist for Blazor
  &lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Explore the &lt;a href="https://blazor.syncfusion.com/demos/inline-ai-assist/overview?theme=fluent2" rel="noopener noreferrer"&gt;Inline AI Assist demo&lt;/a&gt; or follow the &lt;a href="https://blazor.syncfusion.com/documentation/inline-ai-assist/getting-started" rel="noopener noreferrer"&gt;getting started documentation&lt;/a&gt; to add it to your Blazor application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started faster with Syncfusion Blazor templates
&lt;/h2&gt;

&lt;p&gt;Getting a new Blazor project up and running often involves repetitive setup before development can begin. To streamline that process, Syncfusion provides &lt;a href="https://blazor.syncfusion.com/documentation/getting-started/blazor-web-app#using-templates" rel="noopener noreferrer"&gt;.NET templates&lt;/a&gt; that align closely with Microsoft Blazor Web App templates.&lt;/p&gt;

&lt;p&gt;These templates generate a fully configured Blazor application with Syncfusion components, themes, and dependencies already in place.&lt;/p&gt;

&lt;p&gt;Each template includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NuGet package references,&lt;/li&gt;
&lt;li&gt;Theme and script configuration,&lt;/li&gt;
&lt;li&gt;Required namespace imports,&lt;/li&gt;
&lt;li&gt;Project setup and Syncfusion integration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This helps developers spend less time configuring their projects and more time building application features.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI AssistView: Making AI experiences more natural for end users
&lt;/h2&gt;

&lt;p&gt;While the new Inline AI Assist focuses on in-context editing, the existing &lt;a href="https://www.syncfusion.com/blazor-components/blazor-ai-assistview" rel="noopener noreferrer"&gt;Blazor AI AssistView&lt;/a&gt; continues to improve the experience for chat-style AI interactions. In this release, the focus is on making conversations more accessible while giving users greater control over how they interact with AI-generated responses.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use voice instead of typing
&lt;/h3&gt;

&lt;p&gt;Users can now dictate prompts using built-in speech recognition through the &lt;strong&gt;AssistViewSpeechToText&lt;/strong&gt; tags. This removes the need for developers to integrate a separate &lt;a href="https://blazor.syncfusion.com/demos/ai-assistview/ai-speechtotext?theme=fluent2" rel="noopener noreferrer"&gt;speech-to-text solution&lt;/a&gt; for prompt entry.&lt;/p&gt;

&lt;p&gt;Voice input can be particularly useful for mobile users, field employees, or anyone who prefers speaking over typing when interacting with AI. &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%2F07%2FSpeech-to-text-conversion-in-Blazor-AI-AssistView.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%2F07%2FSpeech-to-text-conversion-in-Blazor-AI-AssistView.png" alt="Speech-to-text conversion in Blazor AI AssistView" width="648" height="712"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Speech-to-text conversion in Blazor AI AssistView
  &lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Regenerate and compare responses
&lt;/h3&gt;

&lt;p&gt;AI-generated answers aren’t always perfect on the first attempt. To make refinement easier, users can now regenerate responses and switch between different versions using navigation controls.&lt;/p&gt;

&lt;p&gt;Rather than replacing the previous answer, AI AssistView retains all generated variations in the &lt;strong&gt;RegeneratedResponses&lt;/strong&gt; collection. This makes it easier to compare alternatives and choose the most useful response for the task at hand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Listen to responses with text-to-speech conversion
&lt;/h3&gt;

&lt;p&gt;AI AssistView can now &lt;a href="https://blazor.syncfusion.com/demos/ai-assistview/ai-texttospeech?theme=fluent2" rel="noopener noreferrer"&gt;read responses aloud&lt;/a&gt;, enabling hands-free interaction.&lt;/p&gt;

&lt;p&gt;Developers can configure output settings such as &lt;strong&gt;Language&lt;/strong&gt;, &lt;strong&gt;Voice&lt;/strong&gt;, and &lt;strong&gt;Volume&lt;/strong&gt;, helping tailor the experience to different accessibility and user requirements.&lt;/p&gt;

&lt;p&gt;This is especially valuable for accessibility-focused applications or situations where users need to consume information while multitasking. &lt;/p&gt;

&lt;h3&gt;
  
  
  Add context with file attachments
&lt;/h3&gt;

&lt;p&gt;The 2026 Volume 2 release also adds support for file attachments through the new &lt;strong&gt;&lt;code&gt;AttachedFiles&lt;/code&gt;&lt;/strong&gt; property and customizable &lt;strong&gt;&lt;code&gt;AttachmentTemplate&lt;/code&gt;&lt;/strong&gt;. This allows users to attach supporting documents while giving developers full control over how attachments are presented in the interface.&lt;/p&gt;

&lt;p&gt;A practical example is an AI assistant that analyzes invoices, reports, specifications, or other uploaded documents and uses them as context for generating responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blazor DataGrid: Reduce friction in everyday data management
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.syncfusion.com/blazor-components/blazor-datagrid" rel="noopener noreferrer"&gt;Blazor DataGrid&lt;/a&gt; receives several practical enhancements in this release, focused on tasks users perform every day, such as filtering data, updating records, and exporting results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Filter different data types from one place
&lt;/h3&gt;

&lt;p&gt;Filtering mixed datasets often requires switching between different filter interfaces for text, numeric, and date columns.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://blazor.syncfusion.com/documentation/datagrid/filter-bar" rel="noopener noreferrer"&gt;filter bar&lt;/a&gt; now includes an inline operator selector, and the value editor automatically adapts to the column type. Depending on the field, users will see a text box, numeric editor, date picker, or drop-down list, making &lt;a href="https://blazor.syncfusion.com/demos/datagrid/filtering?theme=fluent2" rel="noopener noreferrer"&gt;filtering&lt;/a&gt; faster and more intuitive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Index.razor&lt;/strong&gt;&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;SfGrid&lt;/span&gt; &lt;span class="na"&gt;TValue=&lt;/span&gt;&lt;span class="s"&gt;"Order"&lt;/span&gt; &lt;span class="na"&gt;DataSource=&lt;/span&gt;&lt;span class="s"&gt;"@Orders"&lt;/span&gt; &lt;span class="na"&gt;AllowPaging=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;AllowFiltering=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;GridFilterSettings&lt;/span&gt; &lt;span class="na"&gt;ShowFilterBarOperator=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;Type=&lt;/span&gt;&lt;span class="s"&gt;"FilterType.FilterBar"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;GridColumns&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;GridColumn&lt;/span&gt; &lt;span class="na"&gt;Field=&lt;/span&gt;&lt;span class="s"&gt;"@nameof(Order.OrderID)"&lt;/span&gt; &lt;span class="na"&gt;HeaderText=&lt;/span&gt;&lt;span class="s"&gt;"Order ID"&lt;/span&gt; &lt;span class="na"&gt;Width=&lt;/span&gt;&lt;span class="s"&gt;"120"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;GridColumn&lt;/span&gt; &lt;span class="na"&gt;Field=&lt;/span&gt;&lt;span class="s"&gt;"@nameof(Order.CustomerID)"&lt;/span&gt; &lt;span class="na"&gt;HeaderText=&lt;/span&gt;&lt;span class="s"&gt;"Customer ID"&lt;/span&gt; &lt;span class="na"&gt;Width=&lt;/span&gt;&lt;span class="s"&gt;"150"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;GridColumn&lt;/span&gt; &lt;span class="na"&gt;Field=&lt;/span&gt;&lt;span class="s"&gt;"@nameof(Order.Freight)"&lt;/span&gt; &lt;span class="na"&gt;HeaderText=&lt;/span&gt;&lt;span class="s"&gt;"Freight"&lt;/span&gt; &lt;span class="na"&gt;Format=&lt;/span&gt;&lt;span class="s"&gt;"C2"&lt;/span&gt; &lt;span class="na"&gt;Width=&lt;/span&gt;&lt;span class="s"&gt;"120"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/GridColumns&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/SfGrid&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is especially useful in business applications where users frequently filter across different data types.&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%2F07%2FBlazor-DataGrid-with-Filter-bar.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%2F07%2FBlazor-DataGrid-with-Filter-bar.png" alt="Blazor DataGrid with Filter bar" width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Blazor DataGrid with Filter bar
  &lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Speed up data entry with single-click editing
&lt;/h3&gt;

&lt;p&gt;For data-entry-heavy applications, even small interaction improvements can save time.&lt;/p&gt;

&lt;p&gt;A new &lt;strong&gt;&lt;code&gt;AllowEditOnSingleClick&lt;/code&gt;&lt;/strong&gt; option lets users start editing a cell with a single click in batch edit mode, eliminating the need for a double-click.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Index.razor&lt;/strong&gt;&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;SfGrid&lt;/span&gt; &lt;span class="na"&gt;TValue=&lt;/span&gt;&lt;span class="s"&gt;"Order"&lt;/span&gt;
        &lt;span class="na"&gt;DataSource=&lt;/span&gt;&lt;span class="s"&gt;"@Orders"&lt;/span&gt;
        &lt;span class="na"&gt;AllowPaging=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
        &lt;span class="na"&gt;Toolbar=&lt;/span&gt;&lt;span class="s"&gt;"@(new List&amp;lt;string&amp;gt;() { "&lt;/span&gt;&lt;span class="err"&gt;Add",&lt;/span&gt; &lt;span class="err"&gt;"Edit",&lt;/span&gt; &lt;span class="err"&gt;"Delete",&lt;/span&gt; &lt;span class="err"&gt;"Update",&lt;/span&gt; &lt;span class="err"&gt;"Cancel"&lt;/span&gt; &lt;span class="err"&gt;})"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;GridEditSettings&lt;/span&gt; &lt;span class="na"&gt;AllowAdding=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
                      &lt;span class="na"&gt;AllowEditing=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
                      &lt;span class="na"&gt;AllowDeleting=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
                      &lt;span class="na"&gt;Mode=&lt;/span&gt;&lt;span class="s"&gt;"EditMode.Batch"&lt;/span&gt;
                      &lt;span class="na"&gt;AllowEditOnSingleClick=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;GridColumns&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;GridColumn&lt;/span&gt; &lt;span class="na"&gt;Field=&lt;/span&gt;&lt;span class="s"&gt;"@nameof(Order.OrderID)"&lt;/span&gt; &lt;span class="na"&gt;HeaderText=&lt;/span&gt;&lt;span class="s"&gt;"Order ID"&lt;/span&gt; &lt;span class="na"&gt;Width=&lt;/span&gt;&lt;span class="s"&gt;"120"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;GridColumn&lt;/span&gt; &lt;span class="na"&gt;Field=&lt;/span&gt;&lt;span class="s"&gt;"@nameof(Order.CustomerID)"&lt;/span&gt; &lt;span class="na"&gt;HeaderText=&lt;/span&gt;&lt;span class="s"&gt;"Customer ID"&lt;/span&gt; &lt;span class="na"&gt;Width=&lt;/span&gt;&lt;span class="s"&gt;"150"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;GridColumn&lt;/span&gt; &lt;span class="na"&gt;Field=&lt;/span&gt;&lt;span class="s"&gt;"@nameof(Order.Freight)"&lt;/span&gt; &lt;span class="na"&gt;HeaderText=&lt;/span&gt;&lt;span class="s"&gt;"Freight"&lt;/span&gt; &lt;span class="na"&gt;Format=&lt;/span&gt;&lt;span class="s"&gt;"C2"&lt;/span&gt; &lt;span class="na"&gt;Width=&lt;/span&gt;&lt;span class="s"&gt;"120"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/GridColumns&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/SfGrid&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In scenarios such as inventory management, finance, or operations dashboards, reducing clicks can make repetitive updates noticeably more efficient.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preserve international characters in CSV exports
&lt;/h3&gt;

&lt;p&gt;CSV exports now support a configurable &lt;strong&gt;Encoding&lt;/strong&gt; property through &lt;strong&gt;&lt;code&gt;ExcelExportProperties&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Using UTF-8 helps ensure names, symbols, accented characters, and multilingual content remain intact when files are opened in different systems or regional environments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Index.razor&lt;/strong&gt;&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;SfGrid&lt;/span&gt; &lt;span class="na"&gt;TValue=&lt;/span&gt;&lt;span class="s"&gt;"Order"&lt;/span&gt;
        &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;ref=&lt;/span&gt;&lt;span class="s"&gt;"Grid"&lt;/span&gt;
        &lt;span class="na"&gt;DataSource=&lt;/span&gt;&lt;span class="s"&gt;"@Orders"&lt;/span&gt;
        &lt;span class="na"&gt;Toolbar=&lt;/span&gt;&lt;span class="s"&gt;"@(new List&amp;lt;string&amp;gt;() { "&lt;/span&gt;&lt;span class="err"&gt;CsvExport"&lt;/span&gt; &lt;span class="err"&gt;})"&lt;/span&gt;
        &lt;span class="na"&gt;AllowExcelExport=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;GridEvents&lt;/span&gt; &lt;span class="na"&gt;OnToolbarClick=&lt;/span&gt;&lt;span class="s"&gt;"ToolbarClick"&lt;/span&gt;
                &lt;span class="na"&gt;TValue=&lt;/span&gt;&lt;span class="s"&gt;"Order"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;GridColumns&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;GridColumn&lt;/span&gt; &lt;span class="na"&gt;Field=&lt;/span&gt;&lt;span class="s"&gt;"@nameof(Order.OrderID)"&lt;/span&gt; &lt;span class="na"&gt;HeaderText=&lt;/span&gt;&lt;span class="s"&gt;"Order ID"&lt;/span&gt; &lt;span class="na"&gt;Width=&lt;/span&gt;&lt;span class="s"&gt;"120"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;GridColumn&lt;/span&gt; &lt;span class="na"&gt;Field=&lt;/span&gt;&lt;span class="s"&gt;"@nameof(Order.CustomerID)"&lt;/span&gt; &lt;span class="na"&gt;HeaderText=&lt;/span&gt;&lt;span class="s"&gt;"Customer ID"&lt;/span&gt; &lt;span class="na"&gt;Width=&lt;/span&gt;&lt;span class="s"&gt;"150"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;GridColumn&lt;/span&gt; &lt;span class="na"&gt;Field=&lt;/span&gt;&lt;span class="s"&gt;"@nameof(Order.Freight)"&lt;/span&gt; &lt;span class="na"&gt;HeaderText=&lt;/span&gt;&lt;span class="s"&gt;"Freight"&lt;/span&gt; &lt;span class="na"&gt;Format=&lt;/span&gt;&lt;span class="s"&gt;"C2"&lt;/span&gt; &lt;span class="na"&gt;Width=&lt;/span&gt;&lt;span class="s"&gt;"120"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/GridColumns&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/SfGrid&amp;gt;&lt;/span&gt;

@code {
    SfGrid&lt;span class="nt"&gt;&amp;lt;Order&amp;gt;&lt;/span&gt;? Grid;
    List&lt;span class="nt"&gt;&amp;lt;Order&amp;gt;&lt;/span&gt; Orders { get; set; }

    public void ToolbarClick(ClickEventArgs args)
    {
        Grid.ExportToCsvAsync(
            new ExcelExportProperties
            {
                Encoding = System.Text.Encoding.UTF8
            }
        );
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is particularly valuable for applications that work with global customer data or multilingual datasets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pivot Table: Build self-service analytics without extra backend work
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.syncfusion.com/blazor-components/blazor-pivot-table" rel="noopener noreferrer"&gt;Blazor Pivot Table&lt;/a&gt; receives several enhancements that make it better suited for self-service analytics and reporting applications.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Built-in CRUD support&lt;/strong&gt; with configurable server-side controller endpoints, allowing developers to connect existing backend services without building custom data management layers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Percentage of running total&lt;/strong&gt; as a new aggregation type, helping users analyze trends and understand how values contribute to cumulative totals over time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Classic layout support in the server-side engine&lt;/strong&gt;, improving consistency and scalability when working with larger datasets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These additions make it easier to build interactive analytics experiences while reducing the amount of custom implementation required.&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%2F07%2FBlazor-Pivot-Table-3.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%2F07%2FBlazor-Pivot-Table-3.png" alt="Enhancements in Blazor Pivot Table" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Enhancements in Blazor Pivot Table
  &lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Charts: Improve readability in dense visualizations
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.syncfusion.com/blazor-components/blazor-charts" rel="noopener noreferrer"&gt;Blazor Charts&lt;/a&gt; component receives two enhancements that help users interpret data more quickly, especially in charts with multiple series or dense time-based data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Display series names directly on the chart
&lt;/h3&gt;

&lt;p&gt;Instead of relying solely on legends, developers can now display series names directly within the chart by setting &lt;strong&gt;&lt;code&gt;SeriesLabelSettings.Visible&lt;/code&gt;&lt;/strong&gt; to &lt;strong&gt;true.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Labels can be customized for position, alignment, formatting, and visibility, helping users identify data series without shifting their focus between the chart and legend.&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%2F07%2FBlazor-Charts-Series-label.webp" 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%2F07%2FBlazor-Charts-Series-label.webp" alt="Series label in Blazor Charts" width="799" height="482"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Series label in Blazor Charts
  &lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For more details, review the &lt;a href="https://blazor.syncfusion.com/documentation/chart/series-label" rel="noopener noreferrer"&gt;series label documentation&lt;/a&gt; and &lt;a href="https://blazor.syncfusion.com/demos/chart/line?theme=fluent2" rel="noopener noreferrer"&gt;Line Chart demo&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create cleaner step charts
&lt;/h3&gt;

&lt;p&gt;A new &lt;strong&gt;&lt;code&gt;ShowRisers&lt;/code&gt;&lt;/strong&gt; option on &lt;strong&gt;&lt;code&gt;ChartSeries&lt;/code&gt;&lt;/strong&gt; allows developers to hide vertical riser lines in step line and step area charts.&lt;/p&gt;

&lt;p&gt;This can reduce visual clutter and make value changes easier to follow, particularly in dense time-series visualizations. The option supports left, right, and center step positions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; See the &lt;a href="https://blazor.syncfusion.com/documentation/chart/chart-types/step-area" rel="noopener noreferrer"&gt;Step Area Chart without riser documentation&lt;/a&gt; and &lt;a href="https://blazor.syncfusion.com/demos/chart/steparea-without-riser?theme=fluent2" rel="noopener noreferrer"&gt;demo&lt;/a&gt; for more insights.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diagram: Better UML modeling and more interactive annotations
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.syncfusion.com/diagram-sdk/blazor-diagram" rel="noopener noreferrer"&gt;Blazor Diagram&lt;/a&gt; component expands its modeling capabilities in this release while giving developers greater control over diagram annotations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create UML class diagrams more easily
&lt;/h3&gt;

&lt;p&gt;Developers can now build &lt;a href="https://blazor.syncfusion.com/demos/diagram/uml-class" rel="noopener noreferrer"&gt;UML class diagrams&lt;/a&gt; with built-in support for common object-oriented design elements, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Classes&lt;/li&gt;
&lt;li&gt;Interfaces&lt;/li&gt;
&lt;li&gt;Enumerations&lt;/li&gt;
&lt;li&gt;Associations&lt;/li&gt;
&lt;li&gt;Aggregations&lt;/li&gt;
&lt;li&gt;Compositions&lt;/li&gt;
&lt;li&gt;Inheritance relationships&lt;/li&gt;
&lt;li&gt;Dependencies&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%2F07%2FDiagram-UML.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%2F07%2FDiagram-UML.png" alt="Creating UML class diagrams using the Blazor Diagram component" width="800" height="484"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Creating UML class diagrams using the Blazor Diagram component
  &lt;p&gt;&lt;/p&gt;

&lt;p&gt;This makes the Diagram component a stronger fit for architecture reviews, system-design tools, and developer-focused applications where software structures need to be visualized and maintained.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make annotations interactive
&lt;/h3&gt;

&lt;p&gt;Annotations can now support &lt;a href="https://blazor.syncfusion.com/demos/diagram/annotations" rel="noopener noreferrer"&gt;user interactions&lt;/a&gt; such as selection, dragging, resizing, and rotation.&lt;/p&gt;

&lt;p&gt;These capabilities are controlled through the annotation’s &lt;a href="https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Diagram.Annotation.html#Syncfusion_Blazor_Diagram_Annotation_Constraints" rel="noopener noreferrer"&gt;Constraints&lt;/a&gt; settings and remain disabled by default, ensuring existing diagrams continue to behave as expected until explicitly enabled.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add clickable hyperlinks to annotations
&lt;/h3&gt;

&lt;p&gt;Annotations can now include &lt;a href="https://blazor.syncfusion.com/demos/diagram/annotations" rel="noopener noreferrer"&gt;hyperlinks&lt;/a&gt; through &lt;a href="https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Diagram.HyperlinkSettings.html" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;HyperlinkSettings&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Developers can define a destination using the &lt;strong&gt;Url&lt;/strong&gt; property, customize the displayed text with the &lt;strong&gt;Content&lt;/strong&gt; property, and control how links open using the &lt;a href="https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Diagram.HyperlinkSettings.html#Syncfusion_Blazor_Diagram_HyperlinkSettings_OpenMode" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;OpenMode&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; property.&lt;/p&gt;

&lt;p&gt;This is particularly useful for linking diagram elements to documentation, specifications, support resources, or related application pages.&lt;/p&gt;

&lt;p&gt;Read the full blog post on the &lt;a href="https://www.syncfusion.com/blogs/post/whats-new-in-blazor-2026-volume-2" rel="noopener noreferrer"&gt;Syncfusion Website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blazor</category>
      <category>ai</category>
      <category>development</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to Integrate React Spreadsheet with Azure Blob Storage for Seamless Excel Management</title>
      <dc:creator>Lucy Muturi</dc:creator>
      <pubDate>Fri, 17 Jul 2026 11:42:19 +0000</pubDate>
      <link>https://dev.to/syncfusion/how-to-integrate-react-spreadsheet-with-azure-blob-storage-for-seamless-excel-management-1m0g</link>
      <guid>https://dev.to/syncfusion/how-to-integrate-react-spreadsheet-with-azure-blob-storage-for-seamless-excel-management-1m0g</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Excel still powers countless business processes, but working with cloud-hosted files often means juggling downloads, edits, and uploads. See how to integrate React Spreadsheet with Azure Blob Storage to let users work with Excel files directly in the browser while keeping everything centralized in the cloud.&lt;/p&gt;

&lt;p&gt;Imagine you’re building a reporting dashboard that stores monthly sales reports in the cloud.&lt;/p&gt;

&lt;p&gt;A user spots an issue in an Excel file, downloads it, makes a quick update, and uploads it again. No big deal, right?&lt;/p&gt;

&lt;p&gt;Now imagine that same process repeated across multiple teams, hundreds of files, and dozens of updates every day. Suddenly, a simple edit turns into a cycle of downloads, uploads, version conflicts, and extra maintenance.&lt;/p&gt;

&lt;p&gt;The bigger question is: &lt;strong&gt;why are users still leaving your application just to update a spreadsheet?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a common challenge in reporting platforms, financial systems, and internal business applications where Excel remains a critical part of daily operations. Without built-in spreadsheet integration, developers often end up creating custom file-handling processes just to manage files stored in the cloud.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore how to integrate &lt;a href="https://azure.microsoft.com/en-us/products/storage/blobs/?msockid=2999cddb42f26a182611db5043dc6b90" rel="noopener noreferrer"&gt;Azure Blob Storage&lt;/a&gt; with the Syncfusion &lt;a href="https://www.syncfusion.com/spreadsheet-editor-sdk/react-spreadsheet-editor" rel="noopener noreferrer"&gt;React Spreadsheet&lt;/a&gt; component, allowing users to open, edit, and save Excel files directly in the browser. The result is a faster, more streamlined experience for users and a simpler file management process for developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does this approach work well for cloud-based Excel file management?
&lt;/h2&gt;

&lt;p&gt;When working with cloud-hosted spreadsheets, the challenge isn’t simply rendering Excel files.&lt;/p&gt;

&lt;p&gt;The real challenge is handling file transfers, serialization, conversion, and storage efficiently while maintaining an experience that users already understand.&lt;/p&gt;

&lt;p&gt;Instead of building custom file-processing layers yourself, it’s worth looking at how the Syncfusion React Spreadsheet component handles these common challenges out of the box.&lt;/p&gt;

&lt;p&gt;It provides built-in APIs for &lt;strong&gt;opening&lt;/strong&gt; and &lt;strong&gt;saving&lt;/strong&gt; workbooks while supporting server-side processing through Syncfusion &lt;a href="https://www.syncfusion.com/document-sdk" rel="noopener noreferrer"&gt;Document Processing Libraries&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open Excel files from multiple sources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-source file loading&lt;/strong&gt;: Open files from local uploads, &lt;a href="https://help.syncfusion.com/document-processing/excel/spreadsheet/react/open-excel-files#open-excel-files-from-url" rel="noopener noreferrer"&gt;external URLs&lt;/a&gt;, &lt;a href="https://help.syncfusion.com/document-processing/excel/spreadsheet/react/open-excel-files#open-excel-files-from-blob-data" rel="noopener noreferrer"&gt;blob data&lt;/a&gt;, &lt;a href="https://help.syncfusion.com/document-processing/excel/spreadsheet/react/open-save#open-an-excel-file-from-base64-string-data" rel="noopener noreferrer"&gt;Base64 strings&lt;/a&gt;, or server endpoints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User-friendly access&lt;/strong&gt;: Open files through the built-in ribbon menu or programmatically through &lt;a href="https://ej2.syncfusion.com/react/documentation/api/spreadsheet/#open" rel="noopener noreferrer"&gt;APIs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deserialization&lt;/strong&gt;: Use the &lt;a href="https://ej2.syncfusion.com/react/documentation/api/spreadsheet/#openfromjson" rel="noopener noreferrer"&gt;openFromJson&lt;/a&gt; method to restore a workbook from JSON while preserving data, formatting, and structure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lifecycle events&lt;/strong&gt;: Use the &lt;a href="https://ej2.syncfusion.com/react/documentation/api/spreadsheet/#beforeopen" rel="noopener noreferrer"&gt;beforeOpen&lt;/a&gt; and &lt;a href="https://ej2.syncfusion.com/react/documentation/api/spreadsheet/#opencomplete" rel="noopener noreferrer"&gt;openComplete&lt;/a&gt; events to implement custom logic and validations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimized loading&lt;/strong&gt;: Improve large-workbook loading performance through efficient processing techniques.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure access&lt;/strong&gt;: Pass custom headers such as authentication tokens when accessing protected resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Format compatibility&lt;/strong&gt;: Supports &lt;strong&gt;.xlsx&lt;/strong&gt;, &lt;strong&gt;.xls&lt;/strong&gt;, &lt;strong&gt;.xlsm&lt;/strong&gt;, &lt;strong&gt;.xlsb&lt;/strong&gt;, and &lt;strong&gt;.csv&lt;/strong&gt; formats.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Save changes back to cloud storage
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flexible save targets&lt;/strong&gt;: Save files locally or send workbook data to backend services using JSON or Blob formats.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intuitive access&lt;/strong&gt;: Save files through the ribbon interface or programmatically through the &lt;a href="https://ej2.syncfusion.com/react/documentation/api/spreadsheet/#save" rel="noopener noreferrer"&gt;API&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serialization&lt;/strong&gt;: Use the &lt;a href="https://ej2.syncfusion.com/react/documentation/api/spreadsheet/#saveasjson" rel="noopener noreferrer"&gt;saveAsJson&lt;/a&gt; method to serialize workbook data for storage or server-side processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server-side conversion&lt;/strong&gt;: Convert serialized workbook data back to Excel using Syncfusion &lt;a href="https://www.syncfusion.com/document-sdk" rel="noopener noreferrer"&gt;Document Processing Libraries&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;*&lt;em&gt;Event hooks&lt;/em&gt;: Customize the save operations with the &lt;a href="https://ej2.syncfusion.com/react/documentation/api/spreadsheet/#beforesave" rel="noopener noreferrer"&gt;beforeSave&lt;/a&gt; and &lt;a href="https://ej2.syncfusion.com/react/documentation/api/spreadsheet/#savecomplete" rel="noopener noreferrer"&gt;saveComplete&lt;/a&gt; events, perfect for logging, validation, or triggering additional actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PDF export options&lt;/strong&gt;: Export spreadsheets as PDF documents while &lt;a href="https://ej2.syncfusion.com/react/documentation/api/spreadsheet/beforeSaveEventArgs/#pdflayoutsettings" rel="noopener noreferrer"&gt;preserving layout&lt;/a&gt; and formatting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These capabilities simplify spreadsheet file handling by reducing the amount of custom code required to load, process, and save Excel files in cloud-based apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To get started, make sure both the frontend and backend pieces are in place. Setting these up first will make the integration steps much easier to follow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend setup
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Step 1: Create the React application
&lt;/h4&gt;

&lt;p&gt;Create a &lt;a href="https://help.syncfusion.com/document-processing/excel/spreadsheet/react/environment-integration/create-react-app" rel="noopener noreferrer"&gt;React project created&lt;/a&gt; using your preferred setup tool, such as &lt;strong&gt;Create React App&lt;/strong&gt; or &lt;strong&gt;Vite.&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Install the Syncfusion React Spreadsheet component
&lt;/h4&gt;

&lt;p&gt;Next, install the React Spreadsheet component:&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-spreadsheet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For additional configuration details, refer to the Syncfusion &lt;a href="https://help.syncfusion.com/document-processing/excel/spreadsheet/react/getting-started" rel="noopener noreferrer"&gt;React Spreadsheet documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: Render the Spreadsheet component
&lt;/h4&gt;

&lt;p&gt;Once the package is installed, add the React Spreadsheet to your app and verify it renders correctly. At this stage, the toolbar and ribbon should be enabled so users can access built-in spreadsheet actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend setup
&lt;/h3&gt;

&lt;p&gt;With the frontend ready, the next step is to configure a backend service that can communicate with Azure Blob Storage and handle Spreadsheet open and save operations.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Create an ASP.NET Core Web API project
&lt;/h4&gt;

&lt;p&gt;Create a new &lt;a href="https://github.com/SyncfusionExamples/EJ2-Spreadsheet-WebServices/tree/main/WebAPI" rel="noopener noreferrer"&gt;ASP.NET Core Web API project&lt;/a&gt;. This service acts as a bridge between the React Spreadsheet component and Azure Blob Storage, handling file retrieval and storage.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Install required NuGet packages
&lt;/h4&gt;

&lt;p&gt;Add the following packages to support Azure Blob Storage integration and Spreadsheet processing:&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 Azure.Storage.Blobs
Install-Package Syncfusion.EJ2.Spreadsheet.AspNet.Core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Configure Azure Blob Storage settings
&lt;/h4&gt;

&lt;p&gt;Azure Blob Storage supports multiple authentication methods, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storage account connection strings,&lt;/li&gt;
&lt;li&gt;Shared Access Signatures (SAS), and&lt;/li&gt;
&lt;li&gt;Managed identities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our blog, the &lt;strong&gt;BlobServiceClient&lt;/strong&gt; is configured using a storage account connection string, while SAS tokens and Managed identities can be used in environments that require more granular or credential-free access control.&lt;/p&gt;

&lt;p&gt;Next, add your Azure Blob Storage configuration to the &lt;strong&gt;appsettings.json&lt;/strong&gt; file. The backend uses these settings to access and manage Excel files stored in your Azure container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;appsettings.json&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"connectionString"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-azure-storage-connection-string"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"containerName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-container-name"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Ensure that the Azure Blob Storage container exists, the required Excel files are uploaded, and the configured connection string has sufficient permissions to access the container. Also, verify storage account networking and access settings to avoid authorization or file access errors. Failure to meet these requirements may result in errors such as &lt;strong&gt;403 AuthorizationFailure&lt;/strong&gt; or &lt;strong&gt;File not found&lt;/strong&gt; during open and save operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you need guidance on setting up the open and save services locally, see our detailed blog: &lt;a href="https://www.syncfusion.com/blogs/post/host-spreadsheet-open-and-save-services" rel="noopener noreferrer"&gt;Hosting open and save services for a Spreadsheet with ASP.NET Core and Docker&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens behind the scenes when users open and save files?
&lt;/h2&gt;

&lt;p&gt;Before diving into the implementation, let’s take a quick look at how spreadsheet data moves between the React app, the ASP.NET Core service, and Azure Blob Storage during open and save operations.&lt;/p&gt;

&lt;p&gt;At a high level, the React Spreadsheet component handles the editing experience, while the ASP.NET Core service manages file processing and communication with Azure Blob Storage. This keeps the browser focused on user interaction while the server handles Excel-specific operations.&lt;/p&gt;

&lt;p&gt;Understanding this flow makes it easier to see how files are retrieved, processed, and stored throughout the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Excel files move from Azure Storage to the browser
&lt;/h3&gt;

&lt;p&gt;When a user opens a spreadsheet, the file is retrieved from cloud storage, processed by the backend, and then loaded into the Spreadsheet component for editing.&lt;/p&gt;

&lt;p&gt;The process typically follows these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client request&lt;/strong&gt;: The React app initiates a request to open an Excel file stored in Azure Blob Storage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File retrieval&lt;/strong&gt;: The ASP.NET Core Web API backend uses the Azure SDK &lt;strong&gt;(Azure.Storage.Blobs)&lt;/strong&gt; to fetch the Excel file from the specified blob container.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workbook processing&lt;/strong&gt;: The backend wraps the downloaded stream in an &lt;a href="https://help.syncfusion.com/cr/aspnetcore-js2/Syncfusion.EJ2.Spreadsheet.OpenRequest.html" rel="noopener noreferrer"&gt;OpenRequest&lt;/a&gt; object and passes it to the &lt;a href="https://help.syncfusion.com/cr/aspnetcore-js2/Syncfusion.EJ2.Spreadsheet.Workbook.html#Syncfusion_EJ2_Spreadsheet_Workbook_Open_Syncfusion_EJ2_Spreadsheet_OpenRequest_" rel="noopener noreferrer"&gt;Workbook.Open&lt;/a&gt; method. This converts the Excel file into a JSON object containing all sheets, formatting, formulas, and styles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load in the Spreadsheet&lt;/strong&gt;: The generated JSON is returned to the frontend, where it is loaded into the React Spreadsheet component using the &lt;a href="https://ej2.syncfusion.com/react/documentation/api/spreadsheet/#openfromjson" rel="noopener noreferrer"&gt;openFromJson&lt;/a&gt; method. &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%2F07%2FAzure-Storage.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%2F07%2FAzure-Storage.png" alt="Azure Storage" width="799" height="207"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Azure Storage
  &lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How Excel files are saved back to Azure Blob Storage
&lt;/h3&gt;

&lt;p&gt;After users finish editing, the updated workbook can be saved back to cloud storage through the backend service.&lt;/p&gt;

&lt;p&gt;The saving process works as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Workbook serialization&lt;/strong&gt;: The React app calls the &lt;a href="https://ej2.syncfusion.com/react/documentation/api/spreadsheet/#saveasjson" rel="noopener noreferrer"&gt;saveAsJson&lt;/a&gt; method to serialize the current workbook state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request preparation&lt;/strong&gt;: The serialized data is packaged into a &lt;strong&gt;&lt;code&gt;FormData&lt;/code&gt;&lt;/strong&gt; object along with details such as the file name, save type, and any optional export settings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workbook generation&lt;/strong&gt;: The ASP.NET Core Web API receives the JSON and uses the &lt;a href="https://help.syncfusion.com/cr/aspnetcore-js2/Syncfusion.EJ2.Spreadsheet.Workbook.html#Syncfusion_EJ2_Spreadsheet_Workbook_Save__1_Syncfusion_EJ2_Spreadsheet_SaveSettings_" rel="noopener noreferrer"&gt;Workbook.Save&lt;/a&gt; method to convert it into an Excel stream.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upload to Azure Blob Storage&lt;/strong&gt;: The backend uploads the Excel stream using the Azure SDK (&lt;strong&gt;&lt;code&gt;BlobClient.UploadAsync&lt;/code&gt;&lt;/strong&gt;), storing it in the specified container with the specified file name and extension.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following diagram illustrates the save process.&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%2F07%2FAzure-Storage-1.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%2F07%2FAzure-Storage-1.png" alt="Azure Storage" width="800" height="244"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Azure Storage
  &lt;p&gt;&lt;/p&gt;

&lt;p&gt;By handling file conversion and storage operations on the server, this approach simplifies Excel file management while keeping the client lightweight. Users can make updates directly within the app without relying on manual download-and-upload steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open cloud-stored Excel files directly in your React app
&lt;/h2&gt;

&lt;p&gt;Now that the architecture is clear, let’s implement the &lt;a href="https://help.syncfusion.com/document-processing/excel/spreadsheet/react/open-excel-files" rel="noopener noreferrer"&gt;file-open&lt;/a&gt; process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create an API endpoint to retrieve files from Azure Blob Storage
&lt;/h3&gt;

&lt;p&gt;On the backend, fetch the Excel file from Azure Blob Storage, convert it to Spreadsheet-compatible JSON by passing the &lt;a href="https://help.syncfusion.com/cr/aspnetcore-js2/Syncfusion.EJ2.Spreadsheet.OpenRequest.html" rel="noopener noreferrer"&gt;OpenRequest&lt;/a&gt; into the &lt;a href="https://help.syncfusion.com/cr/aspnetcore-js2/Syncfusion.EJ2.Spreadsheet.Workbook.html#Syncfusion_EJ2_Spreadsheet_Workbook_Open_Syncfusion_EJ2_Spreadsheet_OpenRequest_" rel="noopener noreferrer"&gt;Open&lt;/a&gt; method, and then return it to the React Spreadsheet component:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SpreadsheetController.cs&lt;/strong&gt;&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;System.IO&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.Threading.Tasks&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;Azure.Storage.Blobs&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;Azure.Storage.Blobs.Specialized&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.Http&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.Mvc&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.Extensions.Configuration&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.Extensions.Logging&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.EJ2.Spreadsheet&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;WebAPI.Controllers&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api/[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&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;SpreadsheetController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//Read Azure Blob Storage settings from configuration&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;BlobServiceClient&lt;/span&gt; &lt;span class="n"&gt;_blobServiceClient&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;_storageContainerName&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;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SpreadsheetController&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Constructor for spreadsheetController&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SpreadsheetController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BlobServiceClient&lt;/span&gt; &lt;span class="n"&gt;blobServiceClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SpreadsheetController&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Store the Blob Service client used to access Azure Blob Storage.&lt;/span&gt;
            &lt;span class="n"&gt;_blobServiceClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;blobServiceClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Store the logger for error tracking and diagnostics.&lt;/span&gt;
            &lt;span class="n"&gt;_logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Retrieve the target container name from application configuration.&lt;/span&gt;
            &lt;span class="n"&gt;_storageContainerName&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="n"&gt;GetValue&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"containerName"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Validate that a container name has been configured.&lt;/span&gt;
            &lt;span class="k"&gt;if&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;IsNullOrEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_storageContainerName&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Configuration 'containerName' is missing or empty."&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="n"&gt;HttpPost&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OpenFromAzure"&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;OpenFromAzure&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FromBody&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;FileOptions&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&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="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MemoryStream&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;new&lt;/span&gt; &lt;span class="nf"&gt;MemoryStream&lt;/span&gt;&lt;span class="p"&gt;())&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;fileName&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;FileName&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;Extension&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="c1"&gt;// Get a reference to the configured Azure Blob Storage container&lt;/span&gt;
                    &lt;span class="n"&gt;BlobContainerClient&lt;/span&gt; &lt;span class="n"&gt;containerClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_blobServiceClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetBlobContainerClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_storageContainerName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="c1"&gt;// Get a reference to the target Excel file (blob) within the container.&lt;/span&gt;
                    &lt;span class="n"&gt;BlockBlobClient&lt;/span&gt; &lt;span class="n"&gt;blockBlobClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;containerClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetBlockBlobClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="c1"&gt;// Validate file existence&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;await&lt;/span&gt; &lt;span class="n"&gt;blockBlobClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExistsAsync&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="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"File not found."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;

                    &lt;span class="c1"&gt;// Download file from Azure Blob Storage&lt;/span&gt;
                    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;blockBlobClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DownloadToAsync&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="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&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;// Wrap stream as FormFile&lt;/span&gt;
                    &lt;span class="n"&gt;OpenRequest&lt;/span&gt; &lt;span class="n"&gt;open&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;OpenRequest&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;File&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;FormFile&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="m"&gt;0&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="n"&gt;Length&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;FileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;};&lt;/span&gt;

                    &lt;span class="c1"&gt;// Convert Excel file to JSON&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="n"&gt;Workbook&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;open&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;Content&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="s"&gt;"application/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="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="c1"&gt;// Log the exception&lt;/span&gt;
                &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogError&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="s"&gt;"Failed to load spreadsheet from Azure Blob Storage."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="c1"&gt;// Return an error response with the exception message.&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StatusCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status500InternalServerError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error occurred while processing the file."&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;// Receives file details from client&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;FileOptions&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;FileName&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="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="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Extension&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="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="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: Load the workbook into the React Spreadsheet
&lt;/h3&gt;

&lt;p&gt;With the API endpoint in place, call it from your React app and load the returned JSON using the &lt;a href="https://ej2.syncfusion.com/react/documentation/api/spreadsheet/#openfromjson" rel="noopener noreferrer"&gt;openFromJson&lt;/a&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.js&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="c1"&gt;// Function to open a spreadsheet file from Azure Blob Storage via an API call&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;openFromAzure&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="nx"&gt;spreadsheet&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="c1"&gt;// Make a POST request to the backend API to fetch the file from Azure Blob Storage. Replace the URL with your local or hosted endpoint URL.&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="s1"&gt;http://localhost: your_port_number/api/spreadsheet/OpenFromAzure&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;method&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="na"&gt;headers&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="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&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;body&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="na"&gt;FileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileInfo&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="c1"&gt;// Name of the file to open&lt;/span&gt;
        &lt;span class="na"&gt;Extension&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extension&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// File extension&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;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="c1"&gt;// Parse the response as JSON&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="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;spreadsheet&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="c1"&gt;// Load the spreadsheet data into the UI&lt;/span&gt;
        &lt;span class="nx"&gt;spreadsheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;openFromJson&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;file&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="na"&gt;triggerEvent&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;showSuccessLoad&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;spreadsheet&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="nf"&gt;showErrorToast&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;h2&gt;
  
  
  Save updates directly to Azure Blob Storage
&lt;/h2&gt;

&lt;p&gt;Once a workbook is loaded into the Spreadsheet component, users can edit it directly in the browser. The next step is to save those updates back to Azure Blob Storage, so the latest version remains available to everyone using the app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Serialize and send workbook data to the cloud
&lt;/h3&gt;

&lt;p&gt;Use the &lt;a href="https://ej2.syncfusion.com/react/documentation/api/spreadsheet/#saveasjson" rel="noopener noreferrer"&gt;saveAsJson&lt;/a&gt; method to serialize the current workbook data and send it to the backend for processing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.js&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="c1"&gt;// Function to save the current spreadsheet to Azure Blob Storage via an API call&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saveToAzure&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;// Convert the current spreadsheet to JSON format&lt;/span&gt;
  &lt;span class="nx"&gt;spreadsheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveAsJson&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;json&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;formData&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;FormData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Append necessary data to the form for the API request&lt;/span&gt;
    &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FileName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loadedFileInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Name of the file to save&lt;/span&gt;
    &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;saveType&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loadedFileInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;saveType&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Save type&lt;/span&gt;
    &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;JSONData&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;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jsonObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Workbook&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Spreadsheet data&lt;/span&gt;
    &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PdfLayoutSettings&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="na"&gt;FitSheetOnOnePage&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="c1"&gt;// PDF layout settings&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Make a POST request to the backend API to save the file to Azure Blob Storage. Replace the URL with your local or hosted endpoint URL.&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="s1"&gt;http://localhost:your_port_number/api/spreadsheet/SaveToAzure&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;method&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="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;formData&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;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="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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;throw&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="s2"&gt;`Save request failed with status &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="nx"&gt;status&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="p"&gt;}&lt;/span&gt;
        &lt;span class="nf"&gt;showSuccessToast&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;showErrorToast&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read the full blog post on the &lt;a href="https://www.syncfusion.com/blogs/post/react-spreadsheet-azure-blob-storage" rel="noopener noreferrer"&gt;Syncfusion Website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>excel</category>
      <category>azure</category>
      <category>cloud</category>
      <category>documentprocessing</category>
    </item>
    <item>
      <title>Building a React Sankey Diagram to Visualize California’s Energy Flow</title>
      <dc:creator>Lucy Muturi</dc:creator>
      <pubDate>Thu, 16 Jul 2026 11:02:19 +0000</pubDate>
      <link>https://dev.to/syncfusion/building-a-react-sankey-diagram-to-visualize-californias-energy-flow-598n</link>
      <guid>https://dev.to/syncfusion/building-a-react-sankey-diagram-to-visualize-californias-energy-flow-598n</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Complex data flows are often difficult to understand when hidden in spreadsheets or traditional charts. See how a &lt;strong&gt;React Sankey Diagram&lt;/strong&gt; transforms California’s energy data into an interactive visualization, helping you uncover flow patterns, energy losses, and key insights with validation, tooltips, responsive layouts, and export support.&lt;/p&gt;

&lt;p&gt;Imagine you’re reviewing an energy report and trying to answer a simple question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where does the energy actually go?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You may have the numbers, but tables and traditional charts often make it difficult to follow how energy moves through the system. A bar chart can compare values, but it can’t easily show how those values split, combine, or eventually reach their destination.&lt;/p&gt;

&lt;p&gt;This is exactly the type of problem that a &lt;strong&gt;Sankey Diagram&lt;/strong&gt; solves.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Sankey Diagram&lt;/strong&gt; visualizes movement between connected stages. The width of each connection represents the quantity being transferred, allowing viewers to immediately identify major contributors, distribution patterns, and losses throughout a process.&lt;/p&gt;

&lt;p&gt;In this tutorial, we’ll use a simplified California energy dataset to build a &lt;a href="https://www.syncfusion.com/react-components/react-sankey" rel="noopener noreferrer"&gt;React Sankey Diagram&lt;/a&gt; with Syncfusion. While the data is intentionally simplified, the implementation approach is the same one you can use in production dashboards, reporting systems, analytics portals, or operational monitoring applications.&lt;/p&gt;

&lt;p&gt;By the end, you’ll have a reusable React component that makes complex flow-based data significantly easier to understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you’ll build
&lt;/h2&gt;

&lt;p&gt;We’ll create an interactive Sankey Diagram that shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Energy originating from sources such as Solar, Wind, Nuclear, Geothermal, Biomass, Coal, Petroleum, and Natural Gas.&lt;/li&gt;
&lt;li&gt;Energy flowing into Electricity Generation.&lt;/li&gt;
&lt;li&gt;Distribution across Residential, Commercial, Industrial, and Transportation sectors.&lt;/li&gt;
&lt;li&gt;Final allocation into Energy Services and Rejected Energy.&lt;/li&gt;
&lt;li&gt;Source-colored links for easier visual tracking.&lt;/li&gt;
&lt;li&gt;Hover tooltips and visible node labels.&lt;/li&gt;
&lt;li&gt;A responsive layout that adapts to different screen sizes.&lt;/li&gt;
&lt;li&gt;Built-in printing and PNG export options.&lt;/li&gt;
&lt;li&gt;Data validation that detects:

&lt;ul&gt;
&lt;li&gt;Duplicate node IDs,&lt;/li&gt;
&lt;li&gt;Broken source or destination references, and&lt;/li&gt;
&lt;li&gt;Invalid flow values.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The final result isn’t just a demo visualization; it’s a foundation you can extend for reporting, operations monitoring, and analytics applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  When a Sankey Diagram makes sense
&lt;/h2&gt;

&lt;p&gt;A Sankey Diagram works best when the primary goal is understanding how something moves through a process.&lt;/p&gt;

&lt;p&gt;Instead of focusing on comparisons or trends, it helps answer questions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where do the largest inputs come from?&lt;/li&gt;
&lt;li&gt;How is a resource distributed?&lt;/li&gt;
&lt;li&gt;Where do losses or bottlenecks occur?&lt;/li&gt;
&lt;li&gt;Which paths carry the most volume?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For scenarios involving movement, allocation, or transformation of data, resources, or energy, a Sankey Diagram often communicates relationships more effectively than traditional charts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If you’re comparing categories, use a bar chart. If you’re showing changes over time, use a line chart. Sankey Diagrams are most useful when the flow itself is the story.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use Syncfusion for a React Sankey Diagram?
&lt;/h2&gt;

&lt;p&gt;You can build a Sankey Diagram from scratch using D3 or SVG, which gives you complete control over the visualization. However, that flexibility comes with the responsibility of maintaining the rendering logic, interactions, and responsive behavior yourself.&lt;/p&gt;

&lt;p&gt;Syncfusion &lt;a href="https://ej2.syncfusion.com/react/documentation/sankey/getting-started" rel="noopener noreferrer"&gt;React Sankey Diagram&lt;/a&gt; offers a component-based alternative that helps you go from structured data to a production-ready visualization much faster. It includes built-in support for labels, legends, tooltips, responsiveness, printing, and exporting, reducing the amount of code you need to build and maintain.&lt;/p&gt;

&lt;p&gt;Choose Syncfusion when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want to quickly transform data into a reusable dashboard component.&lt;/li&gt;
&lt;li&gt;Your application already uses Syncfusion React components and benefits from a consistent look and feel across the UI.&lt;/li&gt;
&lt;li&gt;You prefer a ready-made solution that includes common visualization features out of the box.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A custom D3 or SVG implementation may be a better fit only when your application requires a highly specialized layout or unique interactions that are not available through the component API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you begin, make sure you have &lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; installed, an existing React project, and a basic understanding of React and TypeScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visualizing California’s energy flow pattern using a React Sankey Diagram
&lt;/h2&gt;

&lt;p&gt;Now that the project setup is ready, let’s start building the diagram itself.&lt;/p&gt;

&lt;p&gt;We’ll use a simplified California energy dataset to keep the example focused on the implementation rather than the data. Along the way, we’ll define the data structure, add a validation layer to catch common mistakes, and then render the complete Sankey Diagram with labels, tooltips, legends, printing, and export capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Install the Syncfusion package
&lt;/h3&gt;

&lt;p&gt;To get started, install the Syncfusion React Charts 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-charts &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This package includes the React Sankey Diagram component along with supporting services for features such as tooltips, legends, and exporting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Understand the Sankey data model
&lt;/h3&gt;

&lt;p&gt;Before moving into the chart configuration, it’s helpful to understand how Sankey data is organized.&lt;/p&gt;

&lt;p&gt;Every Sankey Diagram is built from two core pieces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nodes&lt;/strong&gt; represent the entities in your system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Links&lt;/strong&gt; represent the amount moving between those entities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our example, energy sources such as Solar and Natural Gas are nodes. The energy flowing between those sources and other stages in the system is represented by links.&lt;/p&gt;

&lt;p&gt;Once you understand these two building blocks, creating and troubleshooting Sankey Diagrams becomes much easier.&lt;/p&gt;

&lt;p&gt;Each node must have a unique &lt;strong&gt;id&lt;/strong&gt; (&lt;strong&gt;string&lt;/strong&gt;). You can also use &lt;strong&gt;offset&lt;/strong&gt; (&lt;strong&gt;number&lt;/strong&gt;) to adjust its vertical position and &lt;strong&gt;color&lt;/strong&gt; (&lt;strong&gt;string&lt;/strong&gt;) to customize its appearance.&lt;/p&gt;

&lt;p&gt;Each link connects two nodes and requires a &lt;strong&gt;sourceId&lt;/strong&gt; (&lt;strong&gt;string&lt;/strong&gt;), &lt;strong&gt;targetId&lt;/strong&gt; (&lt;strong&gt;string&lt;/strong&gt;), and &lt;strong&gt;value&lt;/strong&gt; (&lt;strong&gt;number&lt;/strong&gt;). The source and target IDs must match existing node IDs, while the value determines the thickness of the link.&lt;/p&gt;

&lt;p&gt;Refer to the following image for a better understanding.&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%2F07%2FSankey-Diagram-nodes-and-links-visualized-as-connected-stages-of-flow.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%2F07%2FSankey-Diagram-nodes-and-links-visualized-as-connected-stages-of-flow.png" alt="Sankey Diagram nodes and links visualized as connected stages of flow" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Sankey Diagram nodes and links visualized as connected stages of flow
  &lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Every &lt;strong&gt;sourceId&lt;/strong&gt; and &lt;strong&gt;targetId&lt;/strong&gt; must match a node id exactly. The strings are &lt;strong&gt;case-sensitive&lt;/strong&gt;, so “&lt;strong&gt;Natural Gas&lt;/strong&gt;” and “&lt;strong&gt;natural gas&lt;/strong&gt;” are treated as two different node references.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Prepare the California energy-flow dataset
&lt;/h3&gt;

&lt;p&gt;For this tutorial, we’ll use a simplified version of a California energy-flow model.&lt;/p&gt;

&lt;p&gt;The dataset is intentionally structured to mirror how energy moves through a real system. Energy starts at primary sources such as &lt;strong&gt;Solar&lt;/strong&gt;, &lt;strong&gt;Wind&lt;/strong&gt;, &lt;strong&gt;Petroleum&lt;/strong&gt;, and &lt;strong&gt;Natural Gas.&lt;/strong&gt; Some of that energy passes through Electricity Generation before reaching end-use sectors such as &lt;strong&gt;Residential&lt;/strong&gt;, &lt;strong&gt;Commercial&lt;/strong&gt;, &lt;strong&gt;Industrial&lt;/strong&gt;, and &lt;strong&gt;Transportation.&lt;/strong&gt; Finally, the flow is divided into useful output and energy losses.&lt;/p&gt;

&lt;p&gt;This structure provides sufficient complexity to demonstrate how Sankey Diagrams handle branching paths, aggregation points, and losses without introducing unnecessary noise in the example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dataset note:&lt;/strong&gt; The values used here have been simplified for demonstration purposes. &lt;a href="https://flowcharts.llnl.gov/commodities/energy" rel="noopener noreferrer"&gt;&lt;strong&gt;Lawrence Livermore National Laboratory (LLNL)&lt;/strong&gt;&lt;/a&gt; publishes detailed state-level energy-flow charts. If you’re building a production solution, replace these values with official data and reference the appropriate chart year.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.ts&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="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;EnergyNode&lt;/span&gt; &lt;span class="o"&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="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;number&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;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;EnergyLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&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;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EnergyNode&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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Solar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#FDB462&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Nuclear&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#80B1D3&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Wind&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#BEBADA&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Geothermal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#8DD3C7&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Natural Gas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#FB8072&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Coal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#8C8C8C&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Biomass&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#B3DE69&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Petroleum&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#BC80BD&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Electricity Generation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#FFD92F&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Residential&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#A6CEE3&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Commercial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#1F78B4&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Industrial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#33A02C&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transportation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#E31A1C&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rejected Energy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#BDBDBD&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Energy Services&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#4DAF4A&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;&lt;strong&gt;Link data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.ts&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;links&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EnergyLink&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Solar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Electricity Generation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;454&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Nuclear&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Electricity Generation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;185&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Wind&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Electricity Generation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;47.8&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Geothermal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Electricity Generation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Natural Gas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Electricity Generation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Coal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Electricity Generation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;28.7&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Biomass&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Electricity Generation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Electricity Generation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Residential&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;182&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Electricity Generation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Commercial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;351&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Electricity Generation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Industrial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;641&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Electricity Generation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transportation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Electricity Generation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rejected Energy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;411.5&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Natural Gas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Residential&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Natural Gas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Commercial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Natural Gas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Industrial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;786&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Natural Gas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transportation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;51&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Biomass&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Industrial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;563&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Biomass&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transportation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;71&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Petroleum&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Residential&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Petroleum&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Industrial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Petroleum&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transportation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2486&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Residential&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rejected Energy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;432&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Residential&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Energy Services&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&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="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Commercial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rejected Energy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;351&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Commercial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Energy Services&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Industrial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rejected Energy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1535&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Industrial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Energy Services&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;755&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transportation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rejected Energy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1991&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transportation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Energy Services&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;637&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: Validate the data before rendering
&lt;/h3&gt;

&lt;p&gt;If you’ve ever spent time debugging a chart that refuses to render, you already know that data issues are often the culprit.&lt;/p&gt;

&lt;p&gt;A single typo in a node ID, a missing reference, or an invalid value can silently break the visualization. These problems are easy to introduce, especially when chart data comes from APIs, spreadsheets, or transformed datasets.&lt;/p&gt;

&lt;p&gt;To avoid that frustration, let’s add a small validation step before rendering. The following helper function checks for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Duplicate node IDs,&lt;/li&gt;
&lt;li&gt;Invalid source or target references,&lt;/li&gt;
&lt;li&gt;Missing, zero, or negative values.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refer to the following code example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.ts&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateSankeyData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EnergyNode&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;links&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EnergyLink&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;nodeIds&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;nodes&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;node&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;node&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;duplicateIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nodes&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;node&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;node&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="nf"&gt;filter&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;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;array&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;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&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;!==&lt;/span&gt; &lt;span class="nx"&gt;index&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;duplicateIds&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;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&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="s2"&gt;`Duplicate node IDs found: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;duplicateIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;invalidLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;links&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&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;!&lt;/span&gt;&lt;span class="nx"&gt;nodeIds&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;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;nodeIds&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;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&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="nx"&gt;invalidLink&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`Invalid Sankey link found: &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;invalidLink&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="kc"&gt;null&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;However, it does not replace full data-quality checks, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Balance validation,&lt;/li&gt;
&lt;li&gt;Circular-flow detection, or&lt;/li&gt;
&lt;li&gt;Source-data auditing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it does catch the kinds of mistakes that commonly lead to broken visualizations and unnecessary debugging sessions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Render the React Sankey Diagram
&lt;/h3&gt;

&lt;p&gt;With the dataset prepared and validated, we can finally render the diagram.&lt;/p&gt;

&lt;p&gt;The component below brings everything together. It validates the dataset, renders the Sankey Diagram, enables tooltips and legends, and adds export and print actions, allowing the chart to be used in both interactive dashboards and reporting scenarios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.ts&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="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;useRef&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;SankeyComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;SankeyNodesCollectionDirective&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;SankeyNodeDirective&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;SankeyLinksCollectionDirective&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;SankeyLinkDirective&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;SankeyTooltip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;SankeyLegend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;SankeyExport&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;@syncfusion/ej2-react-charts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Include the EnergyNode, EnergyLink, validateSankeyData, nodes, and links&lt;/span&gt;
&lt;span class="c1"&gt;// declarations from the earlier sections in the same file, or import them&lt;/span&gt;
&lt;span class="c1"&gt;// from a separate data module.&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;CaliforniaEnergySankey&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;sankeyRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SankeyComponent&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validationError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;validateSankeyData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;links&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;exportAsPng&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="nx"&gt;sankeyRef&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="k"&gt;export&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PNG&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;california-energy-sankey&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;printChart&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="nx"&gt;sankeyRef&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;print&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;validationError&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&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;alert&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;validationError&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="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;section&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;region&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;California energy flow Sankey chart&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;describedby&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;california-energy-sankey-description&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;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;california-energy-sankey-description&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;This&lt;/span&gt; &lt;span class="nx"&gt;Sankey&lt;/span&gt; &lt;span class="nx"&gt;chart&lt;/span&gt; &lt;span class="nx"&gt;shows&lt;/span&gt; &lt;span class="nx"&gt;energy&lt;/span&gt; &lt;span class="nx"&gt;moving&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;primary&lt;/span&gt; &lt;span class="nx"&gt;sources&lt;/span&gt; &lt;span class="nx"&gt;through&lt;/span&gt;
                &lt;span class="nx"&gt;electricity&lt;/span&gt; &lt;span class="nx"&gt;generation&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;sectors&lt;/span&gt; &lt;span class="nx"&gt;into&lt;/span&gt; &lt;span class="nx"&gt;energy&lt;/span&gt; &lt;span class="nx"&gt;services&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt;
                &lt;span class="nx"&gt;rejected&lt;/span&gt; &lt;span class="nx"&gt;energy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;The&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;simplified&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="nx"&gt;tutorial&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;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;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;12px&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;button&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;button&lt;/span&gt;&lt;span class="dl"&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;exportAsPng&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;Export&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;PNG&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;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;button&lt;/span&gt;&lt;span class="dl"&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;printChart&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;marginLeft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8px&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;Print&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;SankeyComponent&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;sankeyRef&lt;/span&gt;&lt;span class="p"&gt;}&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;california-energy-sankey&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;100%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;560px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;California Energy Flow Example&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="nx"&gt;subTitle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Tutorial dataset adapted from LLNL energy-flow concepts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="nx"&gt;linkStyle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
                    &lt;span class="na"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.65&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;curvature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;colorType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Source&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                &lt;span class="p"&gt;}}&lt;/span&gt;
                &lt;span class="nx"&gt;labelSettings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;visible&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;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
                &lt;span class="nx"&gt;tooltip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;enable&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;legendSettings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
                    &lt;span class="na"&gt;visible&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;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bottom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;itemPadding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&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;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;SankeyTooltip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="nx"&gt;SankeyLegend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="nx"&gt;SankeyExport&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;SankeyNodesCollectionDirective&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;nodes&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;node&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;SankeyNodeDirective&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;node&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;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;node&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;offset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offset&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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;node&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="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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/SankeyNodesCollectionDirective&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;SankeyLinksCollectionDirective&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;links&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;link&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;SankeyLinkDirective&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sourceId&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;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;targetId&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;index&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;sourceId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sourceId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                            &lt;span class="nx"&gt;targetId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;targetId&lt;/span&gt;&lt;span class="p"&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;link&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="p"&gt;))}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/SankeyLinksCollectionDirective&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;/SankeyComponent&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;/section&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;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%2F07%2FReact-Sankey-Diagram-with-labels-source-colored-links-legend-and-tooltips-768x386.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%2F07%2FReact-Sankey-Diagram-with-labels-source-colored-links-legend-and-tooltips-768x386.png" alt="Visualizing California’s energy flow data using the React Sankey Diagram" width="768" height="386"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Visualizing California’s energy flow data using the React Sankey Diagram
  &lt;p&gt;&lt;/p&gt;

&lt;p&gt;Read the full blog post on the &lt;a href="https://www.syncfusion.com/blogs/post/view-energy-flow-react-sankey-diagram" rel="noopener noreferrer"&gt;Syncfusion Website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>chart</category>
      <category>datavisualization</category>
      <category>sankeydiagram</category>
    </item>
    <item>
      <title>Building Global Web Apps? Reduce Latency with Edge Computing</title>
      <dc:creator>Lucy Muturi</dc:creator>
      <pubDate>Wed, 15 Jul 2026 11:29:58 +0000</pubDate>
      <link>https://dev.to/syncfusion/building-global-web-apps-reduce-latency-with-edge-computing-248g</link>
      <guid>https://dev.to/syncfusion/building-global-web-apps-reduce-latency-with-edge-computing-248g</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Cut global latency from &lt;strong&gt;~&lt;/strong&gt; 400 ms to under 100 ms by running application logic at the edge. Explore edge functions, real performance benchmarks, cost trade-offs, and when edge computing outperforms traditional serverless for building fast, scalable web apps.&lt;/p&gt;

&lt;p&gt;Imagine a user in Sydney opens your app. Your server in Virginia processes the request, queries a database, and sends a response. The result? &lt;strong&gt;&lt;code&gt;~800 ms&lt;/code&gt;&lt;/strong&gt; latency.&lt;/p&gt;

&lt;p&gt;Now, imagine the same logic running at a nearby edge location, response time drops closer to &lt;strong&gt;&lt;code&gt;50–100 ms&lt;/code&gt;&lt;/strong&gt;. That difference directly impacts user experience, engagement, and conversions.&lt;/p&gt;

&lt;p&gt;Edge computing exists to solve this exact problem: &lt;strong&gt;unpredictable global latency&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Example latency values; actual results depend on user location, network path, provider, workload, and origin distance.&lt;/p&gt;

&lt;p&gt;This guide breaks down how edge computing works, where it fits in modern web architecture, and when it actually makes sense to use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick decision guide
&lt;/h2&gt;

&lt;p&gt;Developers eventually ask: Should I actually use edge computing?&lt;/p&gt;

&lt;p&gt;Here’s a practical framework to help you decide:&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;If your application needs...&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Use&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;td&gt;Edge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Personalization&lt;/td&gt;
&lt;td&gt;Edge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Static pages&lt;/td&gt;
&lt;td&gt;CDN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Video processing&lt;/td&gt;
&lt;td&gt;Cloud&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI inference&lt;/td&gt;
&lt;td&gt;Cloud GPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Geo routing&lt;/td&gt;
&lt;td&gt;Edge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Heavy computation&lt;/td&gt;
&lt;td&gt;Cloud&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real time data sync&lt;/td&gt;
&lt;td&gt;Edge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complex database queries&lt;/td&gt;
&lt;td&gt;Cloud&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Session management&lt;/td&gt;
&lt;td&gt;Edge&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How Edge computing works
&lt;/h2&gt;

&lt;p&gt;Traditional cloud deployments run in a few fixed regions (e.g., &lt;strong&gt;&lt;code&gt;us-east-1&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;eu-west-1&lt;/code&gt;&lt;/strong&gt;). Users connect to the nearest region, but latency varies based on geography, often dramatically.&lt;/p&gt;

&lt;p&gt;Edge computing changes that model.&lt;/p&gt;

&lt;p&gt;Instead of a handful of regions, your application code runs across &lt;strong&gt;hundreds of global edge locations (PoPs)&lt;/strong&gt;. Requests are often served within tens of milliseconds, but total latency depends on network conditions, origin calls, and workload complexity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Edge computing architecture
&lt;/h3&gt;

&lt;p&gt;Here’s how a typical edge request flows through the system:&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%2F07%2FArchitecture-757x1024.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%2F07%2FArchitecture-757x1024.png" alt="Edge Computing Architecture" width="757" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Edge Computing Architecture
  &lt;p&gt;&lt;/p&gt;

&lt;p&gt;The edge layer sits between users and your origin server, handling lightweight logic without a full round trip to your backend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Edge vs CDN vs Cloud
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Technology&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Primary Purpose&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CDN&lt;/td&gt;
&lt;td&gt;Cache and deliver static content globally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud&lt;/td&gt;
&lt;td&gt;Run centralized backend logic (serverless/VMs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Edge&lt;/td&gt;
&lt;td&gt;Execute application logic at distributed locations near users&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; CDN and edge computing have merged. Modern platforms like Cloudflare and Fastly offer both caching (CDN) and edge compute capabilities in one service.&lt;/p&gt;

&lt;p&gt;Think of edge computing as globally distributed serverless functions triggered by HTTP requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Edge computing vs Traditional Serverless (Latency comparison)
&lt;/h2&gt;

&lt;p&gt;Let’s compare a typical request:&lt;/p&gt;

&lt;h3&gt;
  
  
  Traditional Serverless (Single region)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Request travels to region → &lt;strong&gt;&lt;code&gt;100–200 ms&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Cold start → &lt;strong&gt;&lt;code&gt;200–400 ms&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Processing → &lt;strong&gt;&lt;code&gt;~50 ms&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Response return → &lt;strong&gt;&lt;code&gt;100–200 ms&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Total: **&lt;code&gt;400–650 ms+&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Edge execution
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Request hits nearest edge → &lt;strong&gt;&lt;code&gt;~20 ms&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Warm startup → &lt;strong&gt;&lt;code&gt;~0–5 ms&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Processing → &lt;strong&gt;&lt;code&gt;~50 ms&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Response → &lt;strong&gt;&lt;code&gt;~20 ms&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Total: **&lt;code&gt;~90–100 ms&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Example values for illustration; actual performance varies by workload.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key takeaway&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Edge computing doesn’t eliminate latency, it reduces variability and improves latency consistency compared to centralized deployments, but network conditions still affect performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Edge computing platforms: Cloudflare, Vercel, AWS
&lt;/h2&gt;

&lt;p&gt;Cold starts are generally smaller than traditional serverless, but not eliminated. Some platforms (e.g., Lambda@Edge) can still experience noticeable startup latency. Each has trade-offs in runtime limits, ecosystem support, and developer experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Edge computing performance benchmarks (Latency and cost)
&lt;/h2&gt;

&lt;p&gt;Let’s move beyond marketing claims to measurable performance data from production deployments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Latency improvements (Real-world observations)
&lt;/h3&gt;

&lt;p&gt;Testing a simple API endpoint (fetch user preferences, apply business logic, return JSON) across platforms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;US users: &lt;strong&gt;&lt;code&gt;~120 ms&lt;/code&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;code&gt;~45 ms&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;EU users: &lt;strong&gt;&lt;code&gt;~180 ms&lt;/code&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;code&gt;~50–55 ms&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;APAC users: &lt;strong&gt;&lt;code&gt;~450 ms&lt;/code&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;code&gt;~60–70 ms&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Global P99: &lt;strong&gt;&lt;code&gt;~1200 ms&lt;/code&gt;&lt;/strong&gt; → &lt;strong&gt;&lt;code&gt;~75–200 ms&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The biggest gains happen when users are far from your origin.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cost comparison (10M Requests / Month)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Cloudflare Workers: &lt;strong&gt;&lt;code&gt;~$5&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Vercel Edge: &lt;strong&gt;&lt;code&gt;~$15–20&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;AWS Lambda@Edge: &lt;strong&gt;&lt;code&gt;~$7–8&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Deno Deploy: &lt;strong&gt;&lt;code&gt;~$18–20&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Costs vary significantly based on execution time, data transfer, and storage usage. These estimates assume lightweight requests and minimal outbound bandwidth.&lt;/p&gt;

&lt;h3&gt;
  
  
  When Edge becomes cost-effective
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;High global traffic&lt;/li&gt;
&lt;li&gt;Lightweight per-request compute&lt;/li&gt;
&lt;li&gt;Performance directly impacts conversions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For local apps, traditional serverless is often cheaper and simpler.&lt;/p&gt;

&lt;p&gt;Read the full blog post on the &lt;a href="https://www.syncfusion.com/blogs/post/edge-computing-for-web-developers" rel="noopener noreferrer"&gt;Syncfusion Website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>syncfusion</category>
      <category>cloud</category>
      <category>edgecomputing</category>
      <category>serverlessarchitecture</category>
    </item>
    <item>
      <title>Less Custom Code, Smarter Scheduling: What’s New in Pure React Scheduler 2026 Volume 2</title>
      <dc:creator>Lucy Muturi</dc:creator>
      <pubDate>Mon, 13 Jul 2026 11:11:03 +0000</pubDate>
      <link>https://dev.to/syncfusion/less-custom-code-smarter-scheduling-whats-new-in-pure-react-scheduler-2026-volume-2-2hml</link>
      <guid>https://dev.to/syncfusion/less-custom-code-smarter-scheduling-whats-new-in-pure-react-scheduler-2026-volume-2-2hml</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Essential Studio 2026 Volume 2 brings powerful updates to the Pure React Scheduler, including a mobile-friendly Agenda View, time zone support, load-on-demand data loading, resource grouping, and recurring event management. These enhancements help developers build faster, more scalable scheduling applications with less custom code.&lt;/p&gt;

&lt;p&gt;Scheduling is one of those features that looks simple at first glance. In reality, once you start dealing with recurring appointments, multiple resources, users across different time zones, or thousands of events, things become significantly more challenging.&lt;/p&gt;

&lt;p&gt;The latest enhancements in the Syncfusion&lt;sup&gt;®&lt;/sup&gt; &lt;a href="https://www.syncfusion.com/react-components/scheduler" rel="noopener noreferrer"&gt;Pure React Scheduler&lt;/a&gt; component are designed to simplify these challenges. Whether you’re building an appointment booking platform, a healthcare scheduling system, a workforce management solution, or an educational calendar application, these updates help reduce custom development effort while improving scalability, usability, and performance.&lt;/p&gt;

&lt;p&gt;Let’s explore what’s new in the &lt;a href="https://www.syncfusion.com/forums/198475/essential-studio-2026-volume-2-main-release-v34-1-29-is-available-for-download" rel="noopener noreferrer"&gt;Essential Studio 2026 Volume 2&lt;/a&gt; release for the &lt;a href="https://react.syncfusion.com/react-ui/scheduler/overview/?theme=material" rel="noopener noreferrer"&gt;Pure React Scheduler&lt;/a&gt; and see how these additions can help you create scheduling experiences that are easier to maintain, perform well at scale, and deliver a better experience for users.&lt;/p&gt;

&lt;h2&gt;
  
  
  See upcoming events faster with agenda view
&lt;/h2&gt;

&lt;p&gt;Traditional calendar layouts work well on large screens, but they can become difficult to navigate on mobile devices or when multiple appointments overlap. Finding the next event often requires zooming, scrolling, or switching between views.&lt;/p&gt;

&lt;p&gt;The new &lt;a href="https://react.syncfusion.com/react-ui/scheduler/agenda-view/?theme=material" rel="noopener noreferrer"&gt;agenda view&lt;/a&gt; takes a different approach by presenting upcoming appointments as a clean, date-grouped list. Events are arranged chronologically, making it easy to scan what’s coming next without the visual complexity of a traditional calendar grid.&lt;/p&gt;

&lt;p&gt;This view is especially useful when users care more about event details than calendar placement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Designed for everyday scheduling
&lt;/h3&gt;

&lt;p&gt;If you’ve built mobile scheduling screens before, you’ve likely encountered situations where a month or week view becomes cluttered. Agenda view solves that problem by prioritizing readability.&lt;/p&gt;

&lt;p&gt;A healthcare application, for example, can display a doctor’s appointments for the day in a simple schedule. Likewise, a sales manager can quickly review meetings without navigating between multiple calendar views.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why you’ll appreciate it
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Optimized for mobile screens and compact layouts.&lt;/li&gt;
&lt;li&gt;Displays upcoming events clearly with full details.&lt;/li&gt;
&lt;li&gt;Displays appointments in chronological order, grouped by date and sorted by time.&lt;/li&gt;
&lt;li&gt;Makes overlapping events easier to review.&lt;/li&gt;
&lt;li&gt;Supports configurable date ranges to view single or multiple days.&lt;/li&gt;
&lt;li&gt;Supports recurring events seamlessly.&lt;/li&gt;
&lt;li&gt;Includes full keyboard accessibility support.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Example
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;App.tsx&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Scheduler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;EventSettings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AgendaView&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;@syncfusion/react-scheduler&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;fifaEventData&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;./dataSource&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="c1"&gt;//Event data imported from the data source file.&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eventSettings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EventSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;dataSource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fifaEventData&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;Scheduler&lt;/span&gt;
            &lt;span class="nx"&gt;defaultSelectedDate&lt;/span&gt;&lt;span class="o"&gt;=&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
            &lt;span class="nx"&gt;eventSettings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;eventSettings&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;AgendaView&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;/Scheduler&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;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%2F07%2FAgenda-view-in-Pure-React-Scheduler.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%2F07%2FAgenda-view-in-Pure-React-Scheduler.png" alt="Agenda view in Pure React Scheduler" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Agenda view in Pure React Scheduler
  &lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Schedule confidently across time zones
&lt;/h2&gt;

&lt;p&gt;Time zones seem straightforward until users begin joining events from different regions. Hard-coded conversions and custom date calculations can quickly become difficult to maintain.&lt;/p&gt;

&lt;p&gt;The Scheduler now supports both &lt;a href="https://react.syncfusion.com/react-ui/scheduler/timezone/?theme=material" rel="noopener noreferrer"&gt;global scheduler-level time zones and appointment-specific time zones&lt;/a&gt;, ensuring events display accurately regardless of users’ locations.&lt;/p&gt;

&lt;p&gt;Once configured, time conversions happen automatically, reducing the amount of custom logic developers need to implement.&lt;/p&gt;

&lt;h3&gt;
  
  
  A practical example
&lt;/h3&gt;

&lt;p&gt;Imagine a product team scheduling a meeting from &lt;strong&gt;New York&lt;/strong&gt; while participants join from &lt;strong&gt;London, Singapore,&lt;/strong&gt; and &lt;strong&gt;Sydney.&lt;/strong&gt; Each attendee sees the meeting in their local time without any manual conversion.&lt;/p&gt;

&lt;p&gt;This removes one of the most common sources of scheduling mistakes in distributed teams.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does this simplify?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Automatically converts appointments between time zones.&lt;/li&gt;
&lt;li&gt;Displays accurate start and end times for users worldwide.&lt;/li&gt;
&lt;li&gt;Reduces scheduling confusion across regions.&lt;/li&gt;
&lt;li&gt;Supports both scheduler-wide and appointment-level configurations.&lt;/li&gt;
&lt;li&gt;Simplifies global application development.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;App.tsx&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Scheduler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DayView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;EventSettings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MonthView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WeekView&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;@syncfusion/react-scheduler&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;fifaEventData&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;./dataSource&lt;/span&gt;&lt;span class="dl"&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="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timezone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UTC&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;eventSettings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EventSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;dataSource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fifaEventData&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;Scheduler&lt;/span&gt;
      &lt;span class="nx"&gt;defaultSelectedDate&lt;/span&gt;&lt;span class="o"&gt;=&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="nx"&gt;eventSettings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;eventSettings&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;timezone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;timezone&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;DayView&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;WeekView&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;MonthView&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;/Scheduler&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;&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%2F07%2FPure-React-Scheduler-displaying-different-time-zone-options.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%2F07%2FPure-React-Scheduler-displaying-different-time-zone-options.png" alt="Pure React Scheduler displaying different time zone options" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Pure React Scheduler displaying different time zone options
  &lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep large schedules responsive with load-on-demand
&lt;/h2&gt;

&lt;p&gt;As scheduling applications grow, performance can quickly become a challenge. Loading large volumes of appointments upfront increases payload size, slows rendering, and consumes unnecessary resources.&lt;/p&gt;

&lt;p&gt;The new &lt;strong&gt;load-on-demand&lt;/strong&gt; capability solves this by loading only the events needed for the currently visible date range. As users navigate between dates and views, the Scheduler fetches only the relevant data, keeping the experience fast and responsive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two ways to implement it
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Manual data loading with onDataRequest
&lt;/h4&gt;

&lt;p&gt;The &lt;strong&gt;&lt;code&gt;onDataRequest&lt;/code&gt;&lt;/strong&gt; event provides the active view’s start and end dates, allowing you to fetch and return only the events within that range.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Automatic loading with DataManager
&lt;/h4&gt;

&lt;p&gt;The Syncfusion &lt;strong&gt;&lt;code&gt;DataManager&lt;/code&gt;&lt;/strong&gt; can automatically handle data requests during navigation, view changes, and CRUD actions. It sends the active date range to the server, enabling efficient server-side filtering.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real-world use case
&lt;/h3&gt;

&lt;p&gt;Consider a university scheduling system containing thousands of classes across multiple departments. Instead of loading the entire schedule, only the events for the current week or month are retrieved, helping the UI remain responsive as data grows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Reduces API payload sizes.&lt;/li&gt;
&lt;li&gt;Improves rendering speed.&lt;/li&gt;
&lt;li&gt;Minimizes memory usage.&lt;/li&gt;
&lt;li&gt;Handles large datasets efficiently.&lt;/li&gt;
&lt;li&gt;Delivers a faster, more responsive user experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Example
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;App.tsx&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WeekView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Scheduler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;EventSettings&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;@syncfusion/react-scheduler&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;DataManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WebApiAdaptor&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;@syncfusion/react-data&lt;/span&gt;&lt;span class="dl"&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="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&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;DataManager&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://ej2services.syncfusion.com/react/hotfix/api/schedule&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;adaptor&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;WebApiAdaptor&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="na"&gt;crossDomain&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eventSettings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EventSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;dataSource&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="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;Scheduler&lt;/span&gt; &lt;span class="nx"&gt;eventSettings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;eventSettings&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;WeekView&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;/Scheduler&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;Read the full blog post on the &lt;a href="https://www.syncfusion.com/blogs/post/pure-react-scheduler-2026-volume-2" rel="noopener noreferrer"&gt;Syncfusion Website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>essentialstudio</category>
      <category>javascript</category>
      <category>purereact</category>
    </item>
    <item>
      <title>Building Smarter .NET MAUI Apps? See What’s New in Syncfusion 2026 Volume 2</title>
      <dc:creator>Lucy Muturi</dc:creator>
      <pubDate>Fri, 10 Jul 2026 15:45:05 +0000</pubDate>
      <link>https://dev.to/syncfusion/building-smarter-net-maui-apps-see-whats-new-in-syncfusion-2026-volume-2-5a2m</link>
      <guid>https://dev.to/syncfusion/building-smarter-net-maui-apps-see-whats-new-in-syncfusion-2026-volume-2-5a2m</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; The 2026 Volume 2 release brings major enhancements to .NET MAUI, including multi-agent AI AssistView experiences, conversation management, advanced chart visualization, DataGrid productivity improvements, built-in filtering, and TreeView checkbox support. These updates help you build more intelligent, data-driven, and user-friendly cross-platform applications with less custom code and better user experiences.&lt;/p&gt;

&lt;p&gt;Modern applications are evolving rapidly, with growing demand for AI-powered experiences, interactive data visualization, and productivity-focused user interfaces. To help you meet these expectations, the Essential Studio&lt;sup&gt;® &lt;/sup&gt;&lt;a href="https://help.syncfusion.com/common/essential-studio/release-notes/v34.1.29" rel="noopener noreferrer"&gt;2026 Volume 2&lt;/a&gt; release for .NET MAUI introduces enhancements across AI experiences, data management, and visualization.&lt;/p&gt;

&lt;p&gt;This release brings new capabilities that make it easier to build intelligent applications, work with data more effectively, and deliver richer user experiences. From improved AI interactions and conversation management to enhanced charting and productivity-focused data features, these updates help you create modern cross-platform applications with less effort.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td width="132"&gt;&lt;strong&gt;&amp;nbsp;Area&lt;/strong&gt;&lt;/td&gt;
&lt;td width="492"&gt;&lt;strong&gt;&amp;nbsp;Highlights&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td width="132"&gt;&amp;nbsp;&lt;a title=".NET MAUI AI AssistView" href="https://www.syncfusion.com/maui-controls/maui-ai-assistview" rel="noopener noreferrer"&gt;AI AssistView&lt;/a&gt;
&lt;/td&gt;
&lt;td width="492"&gt;&amp;nbsp;Multi-agent support, conversation management, and chat experience enhancements.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td width="132"&gt;&amp;nbsp;&lt;a title=".NET MAUI Cartesian Charts" href="https://www.syncfusion.com/maui-controls/maui-cartesian-charts/chart-types" rel="noopener noreferrer"&gt;Cartesian Charts&lt;/a&gt;
&lt;/td&gt;
&lt;td width="492"&gt;&amp;nbsp;Point color mapping and multilevel labels.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td width="132"&gt;&amp;nbsp;&lt;a title=".NET MAUI DataGrid" href="https://www.syncfusion.com/maui-controls/maui-datagrid" rel="noopener noreferrer"&gt;DataGrid&lt;/a&gt;
&lt;/td&gt;
&lt;td width="492"&gt;&amp;nbsp;Multi-row dragging, built-in search, and undo/redo operations.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td width="132"&gt;&amp;nbsp;&lt;a title=".NET MAUI ListView" href="https://www.syncfusion.com/maui-controls/maui-listview" rel="noopener noreferrer"&gt;ListView&lt;/a&gt;
&lt;/td&gt;
&lt;td width="492"&gt;&amp;nbsp;Built-in filtering UI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td width="132"&gt;&amp;nbsp;&lt;a title=".NET MAUI TreeView" href="https://www.syncfusion.com/maui-controls/maui-treeview" rel="noopener noreferrer"&gt;TreeView&lt;/a&gt;
&lt;/td&gt;
&lt;td width="492"&gt;&amp;nbsp;Easier hierarchical item selection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Let’s explore the highlights of the 2026 Volume 2 release.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI AssistView
&lt;/h2&gt;

&lt;p&gt;AI-powered applications continue to evolve, and this release expands &lt;a href="https://www.syncfusion.com/maui-controls/maui-ai-assistview" rel="noopener noreferrer"&gt;AI AssistView&lt;/a&gt; with features that make it easier than ever to build sophisticated conversational experiences.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent picker
&lt;/h3&gt;

&lt;p&gt;Today’s applications often rely on multiple AI agents, each tailored for a specific task such as document summarization, coding assistance, customer support, or translation. With the new Agent Picker, users can switch between agents directly from the prompt editor without interrupting their workflow.&lt;/p&gt;

&lt;p&gt;The selected agent appears as a compact chip with an icon and label, making it easy to identify the active assistant at a glance.&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%2F07%2FAgent-Picker-in-AI-AssistView.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%2F07%2FAgent-Picker-in-AI-AssistView.gif" alt="Agent Picker support in AI AssistView" width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Agent Picker support in AI AssistView
  &lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conversation management
&lt;/h3&gt;

&lt;p&gt;As AI applications grow, managing conversations becomes just as important as generating responses. The new Conversation Management support enables developers to provide a dedicated conversation panel where users can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pin important conversations&lt;/li&gt;
&lt;li&gt;Rename chats for easier identification&lt;/li&gt;
&lt;li&gt;Filter conversations&lt;/li&gt;
&lt;li&gt;Remove conversations that are no longer needed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates a familiar experience similar to modern AI chat platforms while keeping conversation history organized and accessible.&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%2F07%2FConversation-Management-in-AI-AssistView-1.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%2F07%2FConversation-Management-in-AI-AssistView-1.gif" alt="Conversation Management support in AI AssistView" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Conversation Management support in AI AssistView
  &lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  AI chat experience enhancements
&lt;/h3&gt;

&lt;p&gt;Several usability improvements have also been added to make AI interactions more seamless:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Image Preview&lt;/strong&gt; allows users to open attached images in a larger view for easier inspection of screenshots, diagrams, and other visual content.
&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%2F07%2FImage-Preview-in-AI-AssistView.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%2F07%2FImage-Preview-in-AI-AssistView.gif" alt="Image Preview support in AI AssistView" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Image Preview support in AI AssistView
  &lt;p&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time-based Message Grouping&lt;/strong&gt; automatically organizes conversations into sections such as Today, Yesterday, and earlier dates, making long chat histories easier to navigate.&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%2F07%2FTime-based-Message-Grouping-in-AI-AssistView.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%2F07%2FTime-based-Message-Grouping-in-AI-AssistView.png" alt="Time-based Message Grouping support in AI AssistView" width="780" height="434"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Time-based Message Grouping support in AI AssistView
  &lt;p&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resizable Prompt Input&lt;/strong&gt; provides additional editing space for longer prompts, detailed instructions, and code snippets.&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%2F07%2FResizable-Prompt-Input-in-AI-AssistView.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%2F07%2FResizable-Prompt-Input-in-AI-AssistView.png" alt="Resizable Prompt Input support in AI AssistView" width="780" height="425"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Resizable Prompt Input support in AI AssistView
  &lt;p&gt;&lt;/p&gt;

&lt;p&gt;Together, these enhancements create a more natural and productive chat experience without requiring additional customization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cartesian Charts
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.syncfusion.com/maui-controls/maui-cartesian-charts/chart-types" rel="noopener noreferrer"&gt;Cartesian Charts&lt;/a&gt; control gains new visualization capabilities that help developers present complex information more effectively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Point color mapping
&lt;/h3&gt;

&lt;p&gt;Data often needs visual differentiation to highlight categories, trends, or exceptions. Point Color Mapping allows colors to be assigned directly from the data source using brushes, color values, or hexadecimal color codes.&lt;/p&gt;

&lt;p&gt;This makes it simple to create more expressive charts while keeping configuration straightforward.&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%2F07%2FPoint-Color-Mapping-in-Cartesian-Charts.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%2F07%2FPoint-Color-Mapping-in-Cartesian-Charts.png" alt="Point Color Mapping support in Cartesian Charts" width="781" height="380"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Point Color Mapping support in Cartesian Charts
  &lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Multilevel labels
&lt;/h3&gt;

&lt;p&gt;Large datasets frequently contain multiple layers of categorization. Multilevel Labels help organize axis labels into hierarchical groups, making complex information easier to interpret.&lt;/p&gt;

&lt;p&gt;This enhancement is especially useful for dashboards, scheduling applications, financial reports, and business analytics solutions.&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%2F07%2FMultilevel-Labels-in-Cartesian-Charts.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%2F07%2FMultilevel-Labels-in-Cartesian-Charts.png" alt="Multilevel Labels support in Cartesian Charts" width="780" height="468"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Multilevel Labels support in Cartesian Charts
  &lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  DataGrid
&lt;/h2&gt;

&lt;p&gt;This release introduces several &lt;a href="https://www.syncfusion.com/maui-controls/maui-datagrid" rel="noopener noreferrer"&gt;DataGrid&lt;/a&gt; enhancements focused on improving productivity and reducing the effort required to work with large datasets.&lt;/p&gt;

&lt;h3&gt;
  
  
  Undo and redo support
&lt;/h3&gt;

&lt;p&gt;Data entry mistakes are inevitable, especially when working with large collections of records. Undo and Redo support allows users to quickly reverse or reapply changes, providing greater confidence during editing operations.&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%2F07%2FUndo-and-redo-support-in-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%2F07%2FUndo-and-redo-support-in-DataGrid.gif" alt="Undo and redo support in DataGrid" width="800" height="626"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Undo and redo support in DataGrid
  &lt;p&gt;&lt;/p&gt;

&lt;p&gt;Read the full blog post on the &lt;a href="https://www.syncfusion.com/blogs/post/maui-2026-volume-2-updates" rel="noopener noreferrer"&gt;Syncfusion Website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>netmaui</category>
      <category>crossplatformdevelop</category>
      <category>releasehighlights</category>
      <category>releaseupdates</category>
    </item>
    <item>
      <title>Still Building Custom Chart Builders? Build Runtime Charts with Blazor Chart Wizard</title>
      <dc:creator>Lucy Muturi</dc:creator>
      <pubDate>Fri, 10 Jul 2026 14:09:12 +0000</pubDate>
      <link>https://dev.to/syncfusion/build-runtime-configurable-charts-in-blazor-using-chart-wizard-3e2a</link>
      <guid>https://dev.to/syncfusion/build-runtime-configurable-charts-in-blazor-using-chart-wizard-3e2a</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Building configurable dashboards usually means creating custom chart builders, field selectors, and persistence logic. Learn how the new Blazor Chart Wizard eliminates that work by letting users configure, save, and export charts directly at runtime.&lt;/p&gt;

&lt;p&gt;A dashboard that starts with a simple column chart rarely stays that way.&lt;/p&gt;

&lt;p&gt;Business users eventually ask to switch chart types, compare different metrics, save personalized layouts, and export visualizations without waiting for another development cycle.&lt;/p&gt;

&lt;p&gt;Supporting these requests often requires developers to build configuration panels, field selectors, chart customization interfaces, persistence mechanisms, and export workflows. In many projects, maintaining the chart configuration experience becomes almost as much work as building the dashboard itself.&lt;/p&gt;

&lt;p&gt;The Syncfusion&lt;sup&gt;®&lt;/sup&gt; &lt;a href="https://www.syncfusion.com/blazor-components/blazor-chart-wizard" rel="noopener noreferrer"&gt;Blazor Chart Wizard&lt;/a&gt;, a new component introduced in Essential Studio&lt;sup&gt;® &lt;/sup&gt; &lt;a href="https://help.syncfusion.com/common/essential-studio/release-notes/v34.1.29" rel="noopener noreferrer"&gt;2026 Volume 2&lt;/a&gt; release, takes a different approach.&lt;/p&gt;

&lt;p&gt;Instead of developers defining every chart configuration at design time, Chart Wizard provides a guided runtime experience that allows users to create, customize, save, restore, print, and export charts directly within a Blazor application.&lt;/p&gt;

&lt;p&gt;In this article, you’ll build an Olympic medal dashboard using the Chart Wizard component. Along the way, you’ll learn how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bind business data to Chart Wizard&lt;/li&gt;
&lt;li&gt;Enable runtime chart customization&lt;/li&gt;
&lt;li&gt;Allow users to save and restore chart layouts&lt;/li&gt;
&lt;li&gt;Configure export functionality&lt;/li&gt;
&lt;li&gt;Understand when Chart Wizard is a better choice than a traditional chart component&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end, you’ll have a practical understanding of how Chart Wizard can reduce development effort while delivering more flexibility to end users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just use Syncfusion Chart?
&lt;/h2&gt;

&lt;p&gt;Many Blazor applications already use the &lt;a href="https://www.syncfusion.com/blazor-components/blazor-charts" rel="noopener noreferrer"&gt;SfChart&lt;/a&gt; component to render charts. So why introduce another charting component? The answer comes down to who controls the visualization.&lt;/p&gt;

&lt;p&gt;With the standard chart component, developers define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chart type&lt;/li&gt;
&lt;li&gt;Series configuration&lt;/li&gt;
&lt;li&gt;Axis settings&lt;/li&gt;
&lt;li&gt;Data mappings&lt;/li&gt;
&lt;li&gt;Styling options&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Users interact with the finished chart, but typically cannot modify its structure without changes to the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  When should you use Chart Wizard?
&lt;/h2&gt;

&lt;p&gt;A standard chart component works well when developers control every aspect of the visualization.&lt;/p&gt;

&lt;p&gt;Our Blazor Chart Wizard shines when users need flexibility after deployment.&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;&amp;nbsp;Scenario&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&amp;nbsp;Standard Chart&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&amp;nbsp;Chart Wizard&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;Fixed chart configuration&lt;/td&gt;
&lt;td&gt;&amp;nbsp;Yes&lt;/td&gt;
&lt;td&gt;&amp;nbsp;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;Users switch chart types&lt;/td&gt;
&lt;td&gt;&amp;nbsp;No&lt;/td&gt;
&lt;td&gt;&amp;nbsp;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;Runtime field mapping&lt;/td&gt;
&lt;td&gt;&amp;nbsp;No&lt;/td&gt;
&lt;td&gt;&amp;nbsp;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;Dashboard personalization&lt;/td&gt;
&lt;td&gt;&amp;nbsp;No&lt;/td&gt;
&lt;td&gt;&amp;nbsp;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;Save and restore chart layouts&lt;/td&gt;
&lt;td&gt;&amp;nbsp;No&lt;/td&gt;
&lt;td&gt;&amp;nbsp;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;Lightweight visualization only&lt;/td&gt;
&lt;td&gt;&amp;nbsp;Yes&lt;/td&gt;
&lt;td&gt;&amp;nbsp;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Think of Chart Wizard as a chart-authoring experience rather than a chart control.&lt;/p&gt;

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

&lt;p&gt;The completed sample includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;strong&gt;&lt;code&gt;SfChartWizard&lt;/code&gt;&lt;/strong&gt; component.&lt;/li&gt;
&lt;li&gt;Medal data from the &lt;a href="https://www.olympics.com/en/olympic-games/paris-2024/medals" rel="noopener noreferrer"&gt;Paris 2024&lt;/a&gt; Olympic Games.&lt;/li&gt;
&lt;li&gt;Runtime chart configuration.&lt;/li&gt;
&lt;li&gt;Chart layout persistence using serialization.&lt;/li&gt;
&lt;li&gt;Built-in export capabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is a dashboard where users can experiment with visualizations without requiring application updates.&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%2F07%2FInteractive-Chart-Wizard-Visualization-of-Paris-2024-Olympic-Medal-Standings.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%2F07%2FInteractive-Chart-Wizard-Visualization-of-Paris-2024-Olympic-Medal-Standings.png" alt="Interactive Chart Wizard Visualization of Paris 2024 Olympic Medal Standings" width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Interactive Chart Wizard Visualization of Paris 2024 Olympic Medal Standings
  &lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Chart Wizard fits into a dashboard
&lt;/h2&gt;

&lt;p&gt;In a typical analytics solution, your application remains responsible for retrieving, securing, and validating data.&lt;/p&gt;

&lt;p&gt;Chart Wizard sits on top of that data and provides a user-friendly configuration layer.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                   **Database / API**  
                           ↓  
                 **Application Services**  
                           ↓  
                    **SfChartWizard**  
                           ↓  
                      **End User**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This separation keeps business logic inside your application while giving users freedom to explore data visually.&lt;/p&gt;

&lt;p&gt;New to Chart Wizard? The official &lt;a href="https://blazor.syncfusion.com/documentation/chart-wizard/getting-started" rel="noopener noreferrer"&gt;Getting Started&lt;/a&gt; guide walks you through the complete setup process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building an Olympic medal dashboard with Chart Wizard
&lt;/h2&gt;

&lt;p&gt;Let’s build an interactive Olympic medal dashboard that supports chart customization, layout persistence, and export.&lt;/p&gt;

&lt;h3&gt;
  
  
  Define the data model
&lt;/h3&gt;

&lt;p&gt;Chart Wizard works with standard .NET objects, making it easy to integrate with existing business data. We’ll use a simple model representing Olympic medal standings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&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;OlympicMedalData&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;Country&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="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="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;GoldMedals&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;int&lt;/span&gt; &lt;span class="n"&gt;SilverMedals&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;int&lt;/span&gt; &lt;span class="n"&gt;BronzeMedals&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Prepare sample Olympic medal data
&lt;/h3&gt;

&lt;p&gt;In this example, we’ll use medal data from the &lt;a href="https://www.olympics.com/en/olympic-games/paris-2024/medals" rel="noopener noreferrer"&gt;Paris 2024&lt;/a&gt; Olympics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&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;readonly&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;OlympicMedalData&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MedalRecords&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="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;Country&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="n"&gt;GoldMedals&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SilverMedals&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;44&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;BronzeMedals&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="err"&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;Country&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="n"&gt;GoldMedals&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SilverMedals&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;26&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;BronzeMedals&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;22&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;
  
  
  Configure category and series fields
&lt;/h3&gt;

&lt;p&gt;Next, choose the category and series fields. The Chart Wizard uses category fields for labels and numeric fields for series, helping it determine the best way to visualize your data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&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;readonly&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="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;CategoryFields&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="s"&gt;"Country"&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;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SeriesFields&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="s"&gt;"GoldMedals"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"SilverMedals"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"BronzeMedals"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add the Chart Wizard component
&lt;/h3&gt;

&lt;p&gt;We’ll add the &lt;strong&gt;&lt;code&gt;SfChartWizard&lt;/code&gt;&lt;/strong&gt; component to your Blazor page and bind it to the Olympic medal data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;razor&lt;/strong&gt;&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;@using&lt;/span&gt; &lt;span class="n"&gt;Syncfusion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Blazor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChartWizard&lt;/span&gt; 

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SfChartWizard&lt;/span&gt; &lt;span class="n"&gt;Width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt; &lt;span class="n"&gt;Height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"600px"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ChartSettings&lt;/span&gt; &lt;span class="n"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"@MedalRecords"&lt;/span&gt; 
                   &lt;span class="n"&gt;CategoryFields&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"@CategoryFields"&lt;/span&gt; 
                   &lt;span class="n"&gt;SeriesFields&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"@SeriesFields"&lt;/span&gt; 
                   &lt;span class="n"&gt;SeriesType&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"ChartWizardSeriesType.Column"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;ChartSettings&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;SfChartWizard&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What happens next?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After deployment, users can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Switch chart types.&lt;/li&gt;
&lt;li&gt;Modify series mappings.&lt;/li&gt;
&lt;li&gt;Reconfigure the visualization.&lt;/li&gt;
&lt;li&gt;Explore the data from different perspectives.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without Chart Wizard, supporting these capabilities typically requires building custom interfaces.&lt;/p&gt;

&lt;p&gt;You can use the &lt;strong&gt;&lt;code&gt;SeriesType&lt;/code&gt;&lt;/strong&gt; property to set the initial chart type, while the wizard allows configuration changes to supported chart types at runtime.&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%2F07%2FInteractive-Chart-Wizard-Visualization-of-Paris-2024-Olympic-Medal-Standings.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%2F07%2FInteractive-Chart-Wizard-Visualization-of-Paris-2024-Olympic-Medal-Standings.png" alt="Interactive Chart Wizard Visualization of Paris 2024 Olympic Medal Standings" width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Interactive Chart Wizard Visualization of Paris 2024 Olympic Medal Standings
  &lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Enhance the Chart Wizard with advanced features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Save and restore chart configuration
&lt;/h3&gt;

&lt;p&gt;Users often spend time configuring charts exactly the way they want. Serialization allows those configurations to be saved and restored later.&lt;/p&gt;

&lt;p&gt;Two methods make this possible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;SaveChart()&lt;/code&gt;&lt;/strong&gt;: Serializes the current chart state and returns it as a JSON string.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;LoadChartAsync(string data)&lt;/code&gt;&lt;/strong&gt;: Loads a chart configuration from a JSON string produced by &lt;strong&gt;&lt;code&gt;SaveChart()&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use the following example to wire save and restore buttons.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;razor&lt;/strong&gt;&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;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="err"&gt;="&lt;/span&gt;&lt;span class="nc"&gt;toolbar&lt;/span&gt;&lt;span class="s"&gt;" style="&lt;/span&gt;&lt;span class="n"&gt;margin&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="m"&gt;12&lt;/span&gt;&lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="err"&gt;="&lt;/span&gt;&lt;span class="nc"&gt;btn&lt;/span&gt; &lt;span class="n"&gt;btn&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;primary&lt;/span&gt;&lt;span class="s"&gt;" @onclick="&lt;/span&gt;&lt;span class="n"&gt;SaveChartAsync&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt;Save layout&amp;lt;/button&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="err"&gt;="&lt;/span&gt;&lt;span class="nc"&gt;btn&lt;/span&gt; &lt;span class="n"&gt;btn&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;secondary&lt;/span&gt;&lt;span class="s"&gt;"
&lt;/span&gt;            &lt;span class="n"&gt;@onclick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"LoadChartAsync"&lt;/span&gt;
            &lt;span class="n"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"@string.IsNullOrWhiteSpace(serializedChart)"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;Restore&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;@code&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//……&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SaveChartAsync&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;ChartWizard&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="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;statusMessage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Chart Wizard is not ready yet."&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="n"&gt;serializedChart&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ChartWizard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChart&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;statusMessage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Chart layout saved for this session."&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="k"&gt;private&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;LoadChartAsync&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;ChartWizard&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="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;serializedChart&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;statusMessage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"No saved chart layout is available."&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="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ChartWizard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadChartAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializedChart&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;statusMessage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Saved chart layout restored."&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The serialized output can be stored in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Databases&lt;/li&gt;
&lt;li&gt;Browser storage&lt;/li&gt;
&lt;li&gt;Files&lt;/li&gt;
&lt;li&gt;Cloud storage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes it possible to provide personalized dashboards that survive between sessions.&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%2F07%2FChart-Wizard-with-Serialization.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%2F07%2FChart-Wizard-with-Serialization.png" alt="Chart Wizard with Serialization" width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Chart Wizard with Serialization
  &lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Persist saved chart layouts
&lt;/h3&gt;

&lt;p&gt;When storing chart configurations, remember that applications evolve.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Field names may change.&lt;/li&gt;
&lt;li&gt;Data models may be reorganized.&lt;/li&gt;
&lt;li&gt;Users may load configurations created months earlier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For that reason, consider storing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&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;SavedChartLayout&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;Id&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;UserId&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="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="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;LayoutName&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="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="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;ChartStateJson&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="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="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;DataSchemaVersion&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="s"&gt;"v1"&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;DateTime&lt;/span&gt; &lt;span class="n"&gt;UpdatedUtc&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Save operation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;layout&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;SavedChartLayout&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;UserId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;LayoutName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"My Medal Dashboard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ChartStateJson&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ChartWizard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChart&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;UpdatedUtc&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="n"&gt;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChartLayouts&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;layout&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&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;Load operation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;layout&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChartLayouts&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefaultAsync&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;=&amp;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;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;layoutId&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;ChartWizard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadChartAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChartStateJson&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store a schema version with the layout. If you later rename &lt;strong&gt;&lt;code&gt;GoldMedals&lt;/code&gt;&lt;/strong&gt; to Gold, an old, saved layout may reference a field that no longer exists.&lt;/p&gt;

&lt;h4&gt;
  
  
  Handling invalid saved layouts
&lt;/h4&gt;

&lt;p&gt;Saved layouts can become invalid if fields are renamed, removed, or reorganized after deployment.&lt;/p&gt;

&lt;p&gt;Before calling &lt;strong&gt;&lt;code&gt;LoadChartAsync()&lt;/code&gt;&lt;/strong&gt;, consider validating:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Layout ownership&lt;/li&gt;
&lt;li&gt;Schema version compatibility&lt;/li&gt;
&lt;li&gt;Required fields&lt;/li&gt;
&lt;li&gt;JSON format integrity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If validation fails, notify the user and fall back to a default chart configuration rather than attempting to restore the layout.&lt;/p&gt;

&lt;p&gt;Read the full blog post on the &lt;a href="https://www.syncfusion.com/blogs/post/blazor-chart-wizard" rel="noopener noreferrer"&gt;Syncfusion Website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blazor</category>
      <category>blazorchartwizard</category>
      <category>bashboarddevelopment</category>
      <category>datavisualization</category>
    </item>
    <item>
      <title>Need Faster Document Processing? See What's New in Document SDK 2026 Volume 2</title>
      <dc:creator>Lucy Muturi</dc:creator>
      <pubDate>Wed, 08 Jul 2026 14:48:47 +0000</pubDate>
      <link>https://dev.to/syncfusion/need-faster-document-processing-see-whats-new-in-document-sdk-2026-volume-2-583k</link>
      <guid>https://dev.to/syncfusion/need-faster-document-processing-see-whats-new-in-document-sdk-2026-volume-2-583k</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Struggling with complex document automation or AI integration? Syncfusion Document SDK 2026 Volume 2 introduces AI Agent Tools, Markdown conversion, enhanced OCR, and performance improvements across PDF, Word, Excel, and PowerPoint libraries to help you build faster, smarter, and more reliable document solutions.&lt;/p&gt;

&lt;p&gt;If you’ve ever spent hours maintaining PDF parsers, fixing document conversion issues, or trying to make AI understand complex document content, you’re not alone. Document-heavy applications often become difficult to maintain as requirements grow across formats, platforms, and automation scenarios.&lt;/p&gt;

&lt;p&gt;Syncfusion &lt;a href="https://help.syncfusion.com/common/essential-studio/release-notes/v34.1.29" rel="noopener noreferrer"&gt;Essential Studio&lt;sup&gt;®&lt;/sup&gt; 2026 Volume 2&lt;/a&gt; for &lt;a href="https://help.syncfusion.com/document-processing/release-notes/v34.1.29" rel="noopener noreferrer"&gt;Document Processing&lt;/a&gt; addresses these challenges with AI agent tools, Markdown conversion, and enhancements across PDF, Word, Excel, and PowerPoint libraries.&lt;/p&gt;

&lt;p&gt;Here’s what’s new and why it matters in real-world applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deterministic Document Processing for AI Agents
&lt;/h2&gt;

&lt;p&gt;AI-powered document processes often break down at the same point: document structure. Large language models don’t natively understand PDFs, Word files, or spreadsheets. Teams end up stitching together prompts, parsers, converters, and validators, creating pipelines that are hard to maintain and easy to break.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Agent Tools for the Document SDK
&lt;/h3&gt;

&lt;p&gt;The Syncfusion &lt;a href="https://www.syncfusion.com/explore/ai-agent-tools-for-document-sdk/" rel="noopener noreferrer"&gt;AI Agent Tools&lt;/a&gt; library addresses this by providing AI agents with direct access to reliable, production-ready document operations via callable tools powered by the Syncfusion Document SDK.&lt;/p&gt;

&lt;p&gt;Instead of asking an LLM to “figure out” document structure, agents can now invoke deterministic operations such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PDF:&lt;/strong&gt; Create, convert, redact, sign, merge, and compress PDFs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Word:&lt;/strong&gt; Perform mail merge, track changes, and convert documents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Excel:&lt;/strong&gt; Create charts, work with formulas and pivot tables, and export data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PowerPoint:&lt;/strong&gt; Merge, split, and convert presentations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Office-to-PDF:&lt;/strong&gt; Convert Word, Excel, and PowerPoint files to PDF.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart Data Extraction:&lt;/strong&gt; Extract tables, forms, text, and scanned-image content as structured JSON.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The library runs entirely within your infrastructure on-premises or private cloud and integrates with OpenAI, Azure OpenAI, Claude, or custom orchestration systems. Documents never leave your environment.&lt;/p&gt;

&lt;p&gt;Execution can be handled entirely in memory for low-latency operations or through cloud-backed storage (Azure Blob Storage or Amazon S3) for scalable, stateless processing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-world example:&lt;/strong&gt; An insurance claims application can use AI Agent Tools to extract data from uploaded documents, generate reports, convert files, and archive records without relying on custom parsing logic for each document type.&lt;/p&gt;

&lt;p&gt;Download the &lt;a href="https://www.nuget.org/packages/Syncfusion.DocumentSDK.AI.AgentTools" rel="noopener noreferrer"&gt;AI Agent Tools NuGet&lt;/a&gt; package and extend it with your own custom AI agent tools by cloning the &lt;a href="https://github.com/syncfusion/document-sdk-ai-agent-tools/tree/master/Syncfusion.DocumentSDK.AI.AgentTools" rel="noopener noreferrer"&gt;open-source repository&lt;/a&gt; for the &lt;a href="https://help.syncfusion.com/document-processing/ai-agent-tools/example-use-cases" rel="noopener noreferrer"&gt;real-world use cases&lt;/a&gt;.&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%2F07%2FDocument-SDK-AI-Tools.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%2F07%2FDocument-SDK-AI-Tools.png" alt="Document SDK AI Tools" width="669" height="406"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Document SDK AI Tools
  &lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent Skills: Accurate SDK code inside your IDE
&lt;/h3&gt;

&lt;p&gt;Alongside AI Agent Tools, Document SDK &lt;a href="https://help.syncfusion.com/document-processing/skills/document-sdk" rel="noopener noreferrer"&gt;Agent Skills&lt;/a&gt; focus on developer productivity.&lt;/p&gt;

&lt;p&gt;Agent Skills ground AI coding assistants in verified Syncfusion APIs, eliminating outdated or hallucinated code suggestions. When installed, supported IDEs and assistants can generate accurate, production-ready code using the correct NuGet packages and platform-specific patterns.&lt;/p&gt;

&lt;p&gt;Agent Skills support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Word, PDF, Excel, PowerPoint, Markdown, data extraction, and calculation libraries&lt;/li&gt;
&lt;li&gt;.NET, Java, Flutter, and JavaScript platforms&lt;/li&gt;
&lt;li&gt;Works with GitHub Copilot, Visual Studio Code, Code Studio, Cursor, Claude, and more.&lt;/li&gt;
&lt;li&gt;Two operating modes: Generate code (Mode 1), Execute via csx script (Mode 2)&lt;/li&gt;
&lt;li&gt;One-command installation and granular skill selection&lt;/li&gt;
&lt;li&gt;Auto loaded by supported agents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Depending on the prompt style, developers can either generate ready-to-use code snippets or execute document actions directly via temporary scripts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-world example:&lt;/strong&gt; A development team building a document management system can generate SDK-specific code directly inside their IDE, reducing time spent searching documentation and correcting AI-generated code suggestions.&lt;/p&gt;

&lt;p&gt;Stop building fragile LLM-to-document pipelines from scratch! Explore Syncfusion AI Agent Tools &lt;a href="https://help.syncfusion.com/document-processing/ai-agent-tools/getting-started" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; and Document SDK Agent Skills &lt;a href="https://help.syncfusion.com/document-processing/skills/document-sdk" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; to get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Markdown as a first-class enterprise format
&lt;/h2&gt;

&lt;p&gt;Markdown has become the preferred authoring format for developers and content teams, but most enterprise delivery still happens in Word, Excel, PowerPoint, and PDF. Bridging that gap manually slows everything down.&lt;/p&gt;

&lt;h3&gt;
  
  
  .NET Markdown Library (Preview)
&lt;/h3&gt;

&lt;p&gt;The Syncfusion &lt;a href="https://www.syncfusion.com/document-sdk/net-markdown-library" rel="noopener noreferrer"&gt;.NET Markdown Library&lt;/a&gt; introduces a structured document object model for Markdown, allowing developers to create, read, and edit Markdown programmatically without external dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you can build and format&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Document creation with DOM:&lt;/strong&gt; &lt;a href="https://document.syncfusion.com/demos/markdown/wordtomarkdownconverter#/tailwind" rel="noopener noreferrer"&gt;Create Markdown&lt;/a&gt; documents programmatically using a structured, intuitive object model for clean, maintainable code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich content support:&lt;/strong&gt;  Add and organize Headings, paragraphs, block quotes, thematic breaks, tables, lists, and checkboxes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced text formatting:&lt;/strong&gt;  Apply rich formatting including bold, italic, strikethrough, inline code, subscript, and superscript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Media and linking:&lt;/strong&gt;  Insert images and hyperlinks to enhance document interactivity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code block support:&lt;/strong&gt;  Easily include formatted code blocks for technical documentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Supported conversion:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Seamlessly convert Markdown to and from multiple popular file formats using Syncfusion libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Word documents:&lt;/strong&gt;  Convert &lt;a href="https://help.syncfusion.com/document-processing/word/conversions/markdown-to-word-conversion" rel="noopener noreferrer"&gt;Markdown to Word&lt;/a&gt; and text formats such as .doc, .docx, .xml, &lt;a href="https://www.syncfusion.com/blogs/post/markdown-to-html-csharp-word-library" rel="noopener noreferrer"&gt;.html&lt;/a&gt;, and .rtf, and convert &lt;a href="https://help.syncfusion.com/document-processing/word/conversions/word-to-markdown-conversion" rel="noopener noreferrer"&gt;Word documents to Markdown&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Excel documents:&lt;/strong&gt; Convert &lt;a href="https://help.syncfusion.com/document-processing/excel/conversions/excel-to-markdown/overview" rel="noopener noreferrer"&gt;Excel&lt;/a&gt; files to and from &lt;a href="https://help.syncfusion.com/document-processing/excel/conversions/markdown-to-excel/overview" rel="noopener noreferrer"&gt;Markdown&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PowerPoint presentations:&lt;/strong&gt;  Convert &lt;a href="https://help.syncfusion.com/document-processing/powerpoint/conversions/powerpoint-to-markdown" rel="noopener noreferrer"&gt;PPTX files to Markdown&lt;/a&gt; and generate &lt;a href="https://help.syncfusion.com/document-processing/powerpoint/conversions/markdown-to-powerpoint" rel="noopener noreferrer"&gt;PPTX files from Markdown&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PDF documents:&lt;/strong&gt;  Convert &lt;a href="https://www.syncfusion.com/blogs/post/markdown-to-pdf-in-csharp-word-library" rel="noopener noreferrer"&gt;Markdown to PDF&lt;/a&gt; format and convert &lt;a href="https://help.syncfusion.com/document-processing/data-extraction/net/conversions/pdf-to-markdown" rel="noopener noreferrer"&gt;PDF documents to Markdown&lt;/a&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%2F07%2FMarkdown-File-Format-Conversions.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%2F07%2FMarkdown-File-Format-Conversions.png" alt="Markdown File Format Conversions in .NET Markdown Library" width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Markdown File Format Conversions in .NET Markdown Library
  &lt;p&gt;&lt;/p&gt;

&lt;p&gt;The Syncfusion .NET Markdown Library covers more conversion targets than any comparable lightweight Markdown library, making it the practical choice for teams that need Markdown as a bridge between authoring and enterprise delivery formats.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-world example:&lt;/strong&gt; A documentation platform can store content in Markdown and automatically publish it as Word, PDF, PowerPoint, and Excel files for different audiences without maintaining separate versions of the same content.&lt;/p&gt;

&lt;h2&gt;
  
  
  PDF enhancements across platforms
&lt;/h2&gt;

&lt;h3&gt;
  
  
  .NET PDF Library: HTML-to-PDF security update
&lt;/h3&gt;

&lt;p&gt;HTML-to-PDF remains a core process for invoices, dashboards, and reports. In this release, the Blink binaries used for HTML-to-PDF conversion have been updated to version 147.0.7727.56, which addresses known security vulnerabilities and improves conversion reliability.&lt;/p&gt;

&lt;h3&gt;
  
  
  JavaScript PDF Library: Layout and metadata control
&lt;/h3&gt;

&lt;p&gt;The JavaScript PDF Library now offers deeper layout-level control, enabling more complex client-side PDF generation.&lt;/p&gt;

&lt;p&gt;New capabilities include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Layout-aware text elements&lt;/strong&gt; with styling, alignment, and automatic pagination.&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%2F07%2FLayout%25E2%2580%2591Aware-Text-Elements-in-JavaScript-PDF-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%2F07%2FLayout%25E2%2580%2591Aware-Text-Elements-in-JavaScript-PDF-Library.png" alt="Layout‑Aware Text Elements in JavaScript PDF Library" width="780" height="465"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Layout‑Aware Text Elements in JavaScript PDF Library
  &lt;p&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reusable header and footer templates&lt;/strong&gt; with static content and dynamic fields such as page numbers and dates.&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%2F07%2FReusable-Headers-Footers-in-JavaScript-PDF-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%2F07%2FReusable-Headers-Footers-in-JavaScript-PDF-Library.png" alt="Reusable Headers &amp;amp; Footers in JavaScript PDF Library" width="781" height="446"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Reusable Headers &amp;amp; Footers in JavaScript PDF Library
  &lt;p&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;XMP metadata embedding&lt;/strong&gt; for standardized document indexing, searchability, and archival procedures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more details, check our JavaScript PDF library &lt;a href="https://help.syncfusion.com/document-processing/pdf/pdf-library/javascript/overview" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-world example:&lt;/strong&gt; A reporting application can generate secure, metadata-rich PDF invoices and statements directly from HTML while improving document traceability and searchability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Smarter Data Extraction and OCR control
&lt;/h3&gt;

&lt;h4&gt;
  
  
  .NET Data Extraction Library updates
&lt;/h4&gt;

&lt;p&gt;Accuracy in document extraction often depends on how much control you have over OCR and image handling. This release adds two practical improvements to the Syncfusion &lt;a href="https://www.syncfusion.com/document-sdk/net-pdf-data-extraction" rel="noopener noreferrer"&gt;.NET Data Extraction Library&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom image handling&lt;/strong&gt;: Access extracted images as streams and choose whether to embed them directly in Markdown as base64 or reference them via URLs in cloud storage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configurable OCR settings&lt;/strong&gt;: Fine-tune language selection, OCR engine version, image preprocessing, page segmentation, and multi-language handling before extraction begins.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These controls are especially valuable in healthcare, logistics, and financial processes where extraction accuracy directly affects downstream systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-world example:&lt;/strong&gt; A healthcare provider can extract information from scanned patient records using customized OCR settings, improving recognition accuracy before the data is routed to downstream systems.&lt;/p&gt;

&lt;p&gt;If your extraction pipeline is losing accuracy because OCR settings are locked down, this release gives you the control you’ve been missing. Explore the .NET Data Extraction Library &lt;a href="https://help.syncfusion.com/document-processing/data-extraction/overview" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Excel, Word, and PowerPoint improvements
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.syncfusion.com/document-sdk/net-excel-library" rel="noopener noreferrer"&gt;.NET Excel Library&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://help.syncfusion.com/document-processing/excel/excel-library/net/working-with-pictures#adding-place-in-cell-images" rel="noopener noreferrer"&gt;Place images&lt;/a&gt; directly inside cells so they move and resize naturally with cell changes.&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%2F07%2FImages-Inside-Cells-in-.NET-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%2F07%2FImages-Inside-Cells-in-.NET-Excel-Library.png" alt="Images Inside Cells in .NET Excel Library" width="780" height="577"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Images Inside Cells in .NET Excel Library
  &lt;p&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://help.syncfusion.com/document-processing/excel/conversions/excel-to-markdown/net/excel-to-markdown-conversion" rel="noopener noreferrer"&gt;Convert Excel files&lt;/a&gt; to clean Markdown for documentation or publishing.&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%2F07%2FConvert-Excel-to-Markdown-in-.NET-Excel-Library.jpg" 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%2F07%2FConvert-Excel-to-Markdown-in-.NET-Excel-Library.jpg" alt="Convert Excel to Markdown in .NET Excel Library" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Convert Excel to Markdown in .NET Excel Library
  &lt;p&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://help.syncfusion.com/document-processing/excel/conversions/markdown-to-excel/net/markdown-to-excel-conversion" rel="noopener noreferrer"&gt;Convert Markdown&lt;/a&gt; back into structured Excel data for reporting and analysis.&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%2F07%2FConvert-Markdown-to-Excel-in-.NET-Excel-Library.jpg" 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%2F07%2FConvert-Markdown-to-Excel-in-.NET-Excel-Library.jpg" alt="Convert Markdown to Excel in .NET Excel Library" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;Convert Markdown to Excel in .NET Excel Library
  &lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-world example:&lt;/strong&gt; A financial reporting application can convert spreadsheet data into Markdown for review, then regenerate structured Excel reports from updated content when publishing final results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.syncfusion.com/document-sdk/net-word-library" rel="noopener noreferrer"&gt;.NET Word Library&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Up to &lt;a href="https://help.syncfusion.com/document-processing/word/word-library/net/performance-metrics" rel="noopener noreferrer"&gt;70% faster clone&lt;/a&gt; and merge operations, ideal for high-volume document generation&lt;/li&gt;
&lt;li&gt;Improved HTML parsing with better support for attributes across paragraph and heading tags&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This update delivers immediate, measurable gains for high-volume Word processing workloads. See the Syncfusion .NET Word Library &lt;a href="https://help.syncfusion.com/document-processing/word/word-library/net/overview" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-world example:&lt;/strong&gt; Organizations that generate thousands of personalized contracts or customer letters each day can reduce processing time by accelerating document cloning and merging.&lt;/p&gt;

&lt;p&gt;Read the full blog post on the &lt;a href="https://www.syncfusion.com/blogs/post/document-editor-sdks-2026-volume-2" rel="noopener noreferrer"&gt;Syncfusion Website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>syncfusion</category>
      <category>netdevelopment</category>
      <category>aidocumentworkflows</category>
      <category>developertools</category>
    </item>
  </channel>
</rss>
