<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~files/atom-premium.xsl"?>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedpress="https://feed.press/xmlns" xmlns:media="http://search.yahoo.com/mrss/" xmlns:podcast="https://podcastindex.org/namespace/1.0">
  <feedpress:locale>en</feedpress:locale>
  <link rel="hub" href="https://feedpress.superfeedr.com/"/>
  <logo>https://static.feedpress.com/logo/telerik-blogs-web-react-61850d7ea2a5d.jpg</logo>
  <title type="text">Telerik Blogs | Web | React</title>
  <subtitle type="text">The official blog of Progress Telerik - expert articles and tutorials for developers.</subtitle>
  <id>uuid:2c85066c-0f46-4b6a-8f2f-358b17547d52;id=8277</id>
  <updated>2026-04-23T22:50:00Z</updated>
  <link rel="alternate" href="https://www.telerik.com/"/>
  <link rel="self" type="application/atom+xml" href="https://feeds.telerik.com/blogs/web-react"/>
  <entry>
    <id>urn:uuid:a21016d2-1ad2-4a02-bae7-eef7529852c5</id>
    <title type="text">What’s Next for React in 2026</title>
    <summary type="text">The State of React survey reveals developer insights into the patterns and tools they use and how their opinions about React are shifting.</summary>
    <published>2026-04-20T16:37:09Z</published>
    <updated>2026-04-23T22:50:00Z</updated>
    <author>
      <name>Hassan Djirdeh </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23056/17322393/whats-next-react-2026"/>
    <content type="text"><![CDATA[<p><span class="featured">The State of React survey reveals developer insights into the patterns and tools they use and how their opinions about React are shifting.</span></p><p>The <a target="_blank" href="https://2025.stateofreact.com/">State of React 2025</a> survey results paint an interesting picture of where React stands as it heads into 2026. <a target="_blank" href="https://www.telerik.com/blogs/whats-new-react-19">React 19</a> adoption is well underway, but stability hasn&rsquo;t translated into consensus about what comes next.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/whats-next-for-react-state-of-react-25-survey.png?sfvrsn=952363dc_2" alt="State of React 2025" /></p><p>What the survey shows is that some of React&rsquo;s biggest bets are paying off while others are still finding their footing. The patterns we&rsquo;re building with, the tools we&rsquo;re reaching for and the way we think about React architecture are all shifting. In this article, we&rsquo;ll look at what the data actually says and what it means for the year ahead.</p><h2 id="react-server-components">React Server Components</h2><p>One of the most talked about additions to React in the last couple of years has been <a target="_blank" href="https://react.dev/reference/rsc/server-components">React Server Components (RSC)</a>. Server Components are components that run on the server and let us keep server-only logic, data access and sensitive code out of the client bundle. Alongside that, <a target="_blank" href="https://react.dev/reference/rsc/server-functions">Server Functions</a> let client-side code invoke server-side logic through a framework-managed interface, without hand-rolling traditional API endpoints for every interaction.</p><blockquote><p>For a great read on Server Components, check out <a target="_blank" href="https://www.telerik.com/blogs/current-state-react-server-components-guide-perplexed">The Current State of React Server Components: A Guide for the Perplexed</a>.</p></blockquote><p>Some have said that Server Components were to be the foundation of React&rsquo;s next evolution toward a more complete full-stack framework. The <a target="_blank" href="https://2025.stateofreact.com/en-US/features/#all_features">survey data</a>, however, is more nuanced.</p><p>About 45% of respondents have used Server Components, and among those who have, only about a third report a positive experience. Server Functions tell a similar story, with roughly 37% adoption and 33% positive sentiment among users. In both cases, only a small fraction of the overall community has used these features <em>and</em> come away with a positive sentiment.</p><p>Contrast that with <a target="_blank" href="https://react.dev/reference/react/Suspense">Suspense</a>, React&rsquo;s mechanism for declaratively handling loading states while waiting for asynchronous data or code. <a target="_blank" href="https://2025.stateofreact.com/en-US/features/#new_apis_ratios">Suspense has the highest adoption rate among new features and boasts strong satisfaction numbers</a>.</p><p>It&rsquo;s a useful comparison because it shows that the React community isn&rsquo;t resistant to new patterns: when a new API solves a clear problem with a reasonable developer experience, adoption follows. With that said, Suspense is a smaller, more contained feature that&rsquo;s easier to introduce into existing applications, while Server Components require a more fundamental shift in how we think about our application architecture.</p><p>The architecture data reinforces this picture. <a target="_blank" href="https://2025.stateofreact.com/en-US/usage/#js_app_patterns">When asked which rendering patterns they&rsquo;ve used</a>, most teams still rely on the tried-and-true: Single-Page Applications lead the way at 84%, followed by Server-Side Rendering (61%) and Static Site Generation (44%). Newer approaches like partial hydration (25%), streaming SSR (18%) and islands architecture (14%) are gaining traction, but they&rsquo;re far from mainstream.</p><p>None of this means Server Components don&rsquo;t matter. Architecturally, the ability to move rendering logic to the server, reduce client-side JavaScript and simplify data fetching is significant. But the developer experience may just need more time to mature and catch up to the architectural promise. For most teams, the pragmatic move is to adopt RSC incrementally and where it makes sense, rather than treating it as a mandate to rewrite everything.</p><h2 id="what-developers-are-curious-about">What Developers Are Curious About</h2><p>The survey also gives us a sense of where developer curiosity is headed. The <a target="_blank" href="https://2025.stateofreact.com/en-US/features/#reading_list">reading list</a>, the section of the survey that lets respondents flag topics they want to learn more about, is a useful signal here.</p><p><a href="https://react.dev/reference/react/ViewTransition">ViewTransition</a>, a React API for coordinating animated transitions between UI states, ranks near the top. So does <a target="_blank" href="https://react.dev/reference/react/Activity">Activity</a>, which lets us hide and show parts of our UI while preserving their internal state and DOM. Both are currently only available in React&rsquo;s Canary channel, but they point to a future where React handles more of the UX polish that we currently rely on third-party libraries for.</p><p>What&rsquo;s worth noting is the general pattern across the survey data. The features gaining the most positive attention tend to be the ones that solve focused problems without requiring a wholesale rethink of how we build applications. Developers are drawn to APIs that slot into their existing workflows and make specific things easier, whether that&rsquo;s handling loading states with Suspense, coordinating transitions with <code>&lt;ViewTransition&gt;</code> or managing background rendering with <code>&lt;Activity&gt;</code>.</p><h2 id="the-ui-component-library-landscape">The UI Component Library Landscape</h2><p>The <a target="_blank" href="https://2025.stateofreact.com/en-US/libraries/component-libraries/#component_libraries_cardinalities">survey data around UI component libraries</a> also tells an interesting story. The average respondent has used 2.3 UI libraries and a significant proportion don&rsquo;t use any component library at all. As the survey itself notes, this suggests the space isn&rsquo;t quite settled yet, and that there&rsquo;s still room for new entrants to make their mark.</p><p>What this tells us is that developers are still actively evaluating their options. Even the most widely used libraries in the survey sit around <a target="_blank" href="https://2025.stateofreact.com/en-US/libraries/component-libraries/">50-57% usage</a>, and the libraries with the highest satisfaction rates aren&rsquo;t always the ones with the broadest adoption. The needs are clear: production-quality components, built-in accessibility, consistent theming, TypeScript support and, increasingly, integration with AI-powered development workflows.</p><h3 id="kendoreact">KendoReact</h3><p>For teams building enterprise applications, the choice of component library has long-term implications. It affects how quickly we can ship features, how accessible our applications are out of the box and how well our UI scales across complex use cases like data grids, schedulers and form-heavy workflows.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/whats-next-for-react-kendoreact-home.png?sfvrsn=9f2d81b7_2" alt="KendoReact website: Master the Art of React UI" /></p><p>Progress <a target="_blank" href="https://www.telerik.com/kendo-react-ui">KendoReact</a> is one library worth looking at in this context. It provides <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components">120+ production-ready components</a> with built-in accessibility, deep theming support through <a target="_blank" href="https://www.telerik.com/themebuilder">ThemeBuilder</a> and recent investments in AI-powered developer tooling including an <a target="_blank" href="https://www.telerik.com/react-mcp-servers">MCP server and AI coding assistant</a>. For teams evaluating their UI toolkit for the year ahead, it&rsquo;s a library that&rsquo;s actively investing in the same directions the ecosystem is moving.</p><h2 id="ai-as-an-accelerator">AI as an Accelerator</h2><p>It would be impossible to write about React development in 2026 without mentioning AI. However, the important thing to keep in mind is that AI is changing <strong>how</strong> we write React code, not <strong>what</strong> we build with it.</p><p>The AI tooling landscape has shifted significantly over the last couple of years. AI-native editors like <a target="_blank" href="https://cursor.com/">Cursor</a> and <a target="_blank" href="https://code.claude.com/docs/en/overview">Claude Code</a> understand our entire codebase and can generate components that match our existing patterns and conventions. <a target="_blank" href="https://modelcontextprotocol.io/docs/getting-started/intro">Model Context Protocol (MCP)</a> integrations give AI assistants real-time access to component library documentation, so the code they generate actually uses the right props and follows current best practices.</p><p>These capabilities make us faster by reducing the time we spend on boilerplate and letting us iterate more quickly. However, they don&rsquo;t replace the architectural decisions we need to make: when to adopt Server Components, how to structure our state management and which rendering patterns fit our use case. AI accelerates the execution of those decisions, not the decisions themselves.</p><blockquote><p>For a deeper dive into how AI is reshaping day-to-day React workflows, from code generation to theming to agentic development, check out <a target="_blank" href="https://www.telerik.com/blogs/ai-productivity-react-developers-2026">AI Productivity for React Developers in 2026</a>.</p></blockquote><h2 id="what-this-means-for-2026">What This Means for 2026</h2><p>The data we surveyed today gives us a clear picture of where React is today and where it could be heading in 2026. React is stable, widely adopted and evolving, but the community&rsquo;s appetite for significant change is measured.</p><ul><li><strong>Server Components represent React&rsquo;s most ambitious shift</strong>, but mainstream acceptance will take time. For most teams, the winning approach is incremental adoption, where it solves real problems.</li><li><strong>Developer experience still wins.</strong> The features seeing the strongest adoption and interest (Suspense, ViewTransition, Activity) solve focused problems without demanding that we rebuild our mental model of React.</li><li><strong>The component library landscape remains unsettled.</strong> Teams need libraries that invest in accessibility, developer experience and integrate well with modern tooling, including AI assistants.</li><li><strong>AI is making us more productive at the execution layer</strong>, but strategic decisions about architecture and user experience still require human judgment.</li></ul><p>Looking ahead, the most successful React teams in 2026 will stay pragmatic: adopting new patterns when they solve real problems, choosing stable tooling and using AI to accelerate delivery without losing sight of fundamentals. React&rsquo;s ecosystem is mature enough that we can be selective about what we adopt and when.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">AI Productivity for React Developers in 2026</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Developers are not blindly handing work over to AI, but treating it as a strategic assistant. <a target="_blank" href="https://www.telerik.com/blogs/ai-productivity-react-developers-2026">Here&rsquo;s what this looks like for React devs in 2026.</a></p></div></div></aside><img src="https://feeds.telerik.com/link/23056/17322393.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:156049da-af6d-45bc-9ca5-40a634a963f3</id>
    <title type="text">AI Productivity for React Developers in 2026</title>
    <summary type="text">Developers are not blindly handing work over to AI, but treating it as a strategic assistant. Here’s what this looks like for React devs in 2026.</summary>
    <published>2026-04-13T16:03:30Z</published>
    <updated>2026-04-23T22:50:00Z</updated>
    <author>
      <name>Hassan Djirdeh </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23056/17318469/ai-productivity-react-developers-2026"/>
    <content type="text"><![CDATA[<p><span class="featured">Developers are not blindly handing work over to AI, but treating it as a strategic assistant. Here&rsquo;s what this looks like for React devs in 2026.</span></p><p>The 2025 Stack Overflow Developer Survey confirmed what most of us already know from experience: <a target="_blank" href="https://survey.stackoverflow.co/2025/ai/#1-ai-tools-in-the-development-process">84% of developers are now using or planning to use AI tools in their development process.</a> What&rsquo;s more revealing is how developers are still being cautious in their use of these tools. Only about <a target="_blank" href="https://survey.stackoverflow.co/2025/ai/#2-accuracy-of-ai-tools">one-third say they trust AI outputs completely, while nearly half question their accuracy</a>.</p><p>This cautious adoption tells us something important. We&rsquo;re not blindly handing our work over to AI. We&rsquo;re learning to use these tools strategically, treating them as assistants rather than replacements. For React developers specifically, this means adapting how we approach building interfaces, managing component libraries and iterating on features.</p><p>If you&rsquo;ve been building React applications for a while, you&rsquo;ve probably experienced this shift firsthand. Maybe you&rsquo;re using <a target="_blank" href="https://github.com/features/copilot">GitHub Copilot</a> to autocomplete component logic, or <a target="_blank" href="https://cursor.com/">Cursor</a> to refactor entire feature branches. Perhaps you&rsquo;re generating design themes with <a target="_blank" href="https://www.telerik.com/themebuilder">Progress ThemeBuilder</a>, or using <a target="_blank" href="https://claude.ai/">Claude</a> to debug complex state management issues. These aren&rsquo;t experimental workflows anymore; they&rsquo;re part of how we work.</p><p>In this article, we&rsquo;ll explore what this actually looks like in practice for React developers in 2026.</p><h2 id="coding-itself-has-changed">Coding Itself Has Changed</h2><p>There&rsquo;s a shift in how we write code, and it&rsquo;s not what most people expected (don&rsquo;t worry, we&rsquo;re not being replaced by AI). We&rsquo;re spending less time on the mechanical act of typing and more time on the creative work of guiding and refining.</p><p><a target="_blank" href="https://tinyclouds.org/">Ryan Dahl</a>, the creator of <a target="_blank" href="https://nodejs.org/en">Node.js</a> and <a target="_blank" href="https://deno.com/">Deno</a>, aptly put it in a recent social media post: <em>&ldquo;This has been said a thousand times before, but allow me to add my own voice: the era of humans writing code is over. Disturbing for those of us who identify as SWEs, but no less true. That&rsquo;s not to say SWEs don&rsquo;t have work to do, but writing syntax directly is not it.&rdquo;</em></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/ai-productivity-for-react-ryan-dahl-x-post.png?sfvrsn=6d572b2c_2" alt="" /></p><p>For React developers, this means our day-to-day work looks different. Instead of spending an hour carefully typing out a form component with all its validation logic, we might spend 10 minutes describing what we need and then another 20 minutes reviewing and adjusting the generated code. The result? The same quality component in a fraction of the time.</p><p>The iteration cycles have also become faster. When we can generate and refine code quickly, we&rsquo;re more willing to try multiple approaches. Need to see how our data grid looks with server-side pagination versus client-side? Generate both implementations and compare them. Want to experiment with different state management patterns? We can prototype each one in minutes rather than hours.</p><p>We still need to understand React&rsquo;s rendering model, still need to know when to use <code>useCallback</code> versus <code>useMemo</code>, still need to architect our component hierarchy thoughtfully. However, we don&rsquo;t need to manually type out every property definition or write boilerplate code repeatedly.</p><h2 id="continuous-context-and-ai-native-editors">Continuous Context and AI-Native Editors</h2><p>One of the significant improvements in AI-assisted development is <strong>persistent context</strong>. Modern AI coding assistants understand our entire codebase, not just the file we&rsquo;re currently editing.</p><p>Traditional autocomplete tools could only see a few lines around our cursor. They might suggest completing a function name, but they had no idea what that function should actually do or how it fit into our broader application architecture. AI-native editors and tools like <a target="_blank" href="https://cursor.com/">Cursor</a>, <a target="_blank" href="https://code.claude.com/docs/en/overview">Claude Code</a> and others have changed this completely.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/ai-productivity-for-react-cursor.jpg?sfvrsn=e557aff2_2" alt="" /></p><p>These tools help maintain an understanding of our project structure, our component patterns, our naming conventions and even our coding style. When we ask them to create a new feature, they don&rsquo;t just generate generic React code; they generate code that looks like it belongs in our codebase because they&rsquo;ve learned from the rest of our application.</p><p>Let&rsquo;s say we&rsquo;re building a <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/sample-applications/admin-dashboard">React dashboard</a> UI that needs to fetch user data and display it in a <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/grid">table</a>. With traditional tools, we&rsquo;d manually wire up the API call, handle loading states, manage errors and set up the table structure.</p><p>With an AI assistant that understands our codebase, we can describe what we need, and it&rsquo;ll generate code that uses our existing API client, follows our established error handling patterns and implements the table using whatever libraries we&rsquo;re already using in our app.</p><p>Working with these AI assistants feels less like using a tool and more like pair programming with someone who already knows our codebase inside and out.</p><h2 id="planning-and-agentic-workflows">Planning and Agentic Workflows</h2><p>Writing individual functions or components is one thing, but modern AI tools are increasingly capable of handling multi-step workflows that require planning and coordination. This is where agentic AI comes in: systems that can break down complex tasks into smaller steps and execute them sequentially or in parallel.</p><p>For React developers, this means we can hand off entire features to an AI agent rather than just asking for help with specific files. Want to migrate from <a target="_blank" href="https://redux.js.org/">Redux</a> to <a target="_blank" href="https://github.com/pmndrs/zustand">Zustand</a>? An AI agent can analyze our current state management setup, create a migration plan, and then systematically work through each component to update the implementation.</p><p>For example, we might tell an agent: <em>&ldquo;Build a column chart that shows quarterly sales by region, with drill-down functionality to reveal monthly data when a quarter is clicked.&rdquo;</em></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/kendoreact-chart-mcp.gif?sfvrsn=86c7ffc8_1" alt="" /></p><p>The agent can generate the chart component, configure the data bindings, create any necessary helper functions for aggregation and even add default styling or tooltips.</p><p>What&rsquo;s powerful is that these agents can handle refactors and migrations that would be tedious to do manually. Need to rename a prop across 50 components? Want to update all your class components to functional components with hooks? Planning to migrate from JavaScript to TypeScript? These are exactly the kinds of repetitive-but-important tasks that agents excel at.</p><h2 id="ui-generation-design-and-theming-with-ai">UI Generation, Design and Theming with AI</h2><p>Building user interfaces has always involved a fair amount of repetitive work. Creating layouts, styling components and maintaining design consistency across an application. These are all necessary tasks, but they&rsquo;re not where some developers want to spend their creative energy.</p><p>With AI, layout generation has become surprisingly sophisticated. Tools like <a target="_blank" href="https://v0.dev/">v0</a> can take a description or even a screenshot of a design and generate React components that implement that layout. The code they produce isn&rsquo;t just a rough approximation either, it&rsquo;s good-quality JSX with proper semantic HTML, accessibility attributes and responsive styling.</p><p>For React developers working with component libraries like <a target="_blank" href="https://www.telerik.com/kendo-react-ui">Progress KendoReact</a>, this gets even more powerful as long as the agent has the appropriate context about the library and components. Instead of generating generic HTML and CSS, these tools can generate code using the actual components from our library. Need a data grid with sorting, filtering and pagination? Describe it, and the AI will scaffold it using the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/grid">React Grid</a> component we&rsquo;re already using elsewhere in our app: with all the right props, event handlers and styling.</p><p><a target="_blank" href="https://www.telerik.com/themebuilder">Progress ThemeBuilder</a> has taken this a step further with AI-powered theme generation. Instead of manually configuring dozens of color variables and spacing values, we can describe the aesthetic we&rsquo;re going for in plain English: <em>&ldquo;Create a clean, modern analytics theme with a cool blue-gray palette that feels data-driven and professional, suitable for a B2B software dashboard.&rdquo;</em> The AI generates a complete design system that applies consistently across all our components.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/theme-builder-modern-analytics-theme.png?sfvrsn=8a4ac335_2" alt="" /></p><p>What makes this valuable is that the generated themes aren&rsquo;t just random color combinations. The AI understands design principles like color theory, contrast ratios for accessibility and how different UI states should relate visually. When it generates a theme, it&rsquo;s creating a system where primary buttons, hover states, focus indicators and disabled states all work together. ThemeBuilder also provides component-level AI theming, which means we can refine specific components without having to regenerate our entire theme.</p><p>For developers who aren&rsquo;t designers (which is most of us), this removes a huge source of friction. We can focus on building functionality while still delivering applications that look professional and cohesive.</p><h2 id="model-context-protocol-and-integration">Model Context Protocol and Integration</h2><p>The tools we&rsquo;ve talked about so far are impressive, but they have a limitation: they only know what&rsquo;s in our codebase and what they learned during training. They don&rsquo;t know about our specific component library&rsquo;s latest features, our company&rsquo;s internal design system, or the proprietary APIs we&rsquo;re building against.</p><p>This is where <a target="_blank" href="https://modelcontextprotocol.io/docs/getting-started/intro">Model Context Protocol (MCP)</a> becomes important. Think of MCP as a standardized way for AI models to connect to external knowledge sources and tools. Instead of the AI being limited to its training data, it can reach out to documentation, component libraries, databases and other resources to get current, specific information about the tools we&rsquo;re using.</p><p>For React developers, this means our AI assistant can understand the actual API of the components we&rsquo;re working with, not just generic React patterns. When we&rsquo;re using the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/grid">KendoReact Grid</a> component, an MCP-enabled assistant can query the real documentation to understand what props are available, what patterns are recommended and what changed in the latest version.</p><p>The <a target="_blank" href="https://www.npmjs.com/package/@progress/kendo-react-mcp">@progress/kendo-react-mcp</a> server implements this for KendoReact. When we install it and configure it with our editor, the AI assistant gains access to comprehensive knowledge about KendoReact components. It&rsquo;s not guessing at how to use the Grid, or the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/scheduler">Scheduler</a>, or the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/dateinputs/datepicker">DatePicker</a>. It&rsquo;s referencing the actual documentation and best practices.</p><p>Here&rsquo;s an example of generating a KendoReact Grid from scratch with the help of the <code>@progress/kendo-react-mcp</code> tool.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/kendoreact-grid-mcp.gif?sfvrsn=98fc03b_2" alt="" /></p><p>This can make a large difference in practice. Without MCP, we might ask an AI to create a KendoReact Grid component and get something that looks right but uses outdated props or misses important configuration options. With MCP, the AI generates code that follows current best practices and uses the component exactly as it was designed to be used.</p><h2 id="quality-review-and-governance">Quality, Review and Governance</h2><p>As AI-generated code becomes more prevalent in React applications, questions about quality and review processes naturally arise. The good news is that AI isn&rsquo;t just generating code; it&rsquo;s starting to get better at reviewing and improving it.</p><p>Modern AI tools can perform code reviews that go beyond syntax checking. They understand architectural patterns, can spot potential performance issues and flag accessibility concerns. When we commit changes, these tools can analyze the diff and provide feedback similar to what a developer might offer in a pull request review.</p><p>For React applications specifically, this means AI can catch issues like unnecessary re-renders, missing dependency arrays in hooks, improper state management patterns or components that should be memoized but aren&rsquo;t. It can also verify that our components follow established patterns in our codebase and flag when new code deviates from those conventions.</p><p>AI-generated code can greatly accelerate development and improve consistency, but <strong>it&rsquo;s not a replacement for human judgment</strong>. Even the more sophisticated tools benefit from a steward: a developer who reviews, guides and validates the AI&rsquo;s output. Humans remain essential for making nuanced decisions, verifying alignment with project goals and upholding quality standards that AI alone can&rsquo;t fully guarantee. In other words, AI can handle the heavy (repetitive) lifting, but the final responsibility still rests with us.</p><h2 id="what-this-means-for-day-to-day-react-work">What This Means for Day-to-Day React Work</h2><p>What does all of this actually look like in practice? How has the daily experience of building React applications changed? Here are some takeaways:</p><ul><li><strong>Faster iteration</strong>: Features that used to take days can now be scaffolded in hours. AI handles repetitive boilerplate, letting us focus on logic, architecture and user experience.</li><li><strong>Less boilerplate, more creativity</strong>: Forms, API integrations, responsive layouts and other common patterns can be generated automatically, freeing us to solve higher-level problems.</li><li><strong>Higher-level decisions matter more</strong>: Understanding React fundamentals like component composition, state management, performance optimization and accessibility is more important than ever because we&rsquo;re guiding and reviewing AI outputs rather than typing everything ourselves.</li></ul><p>In short, React development in 2026 is faster, more iterative and more creative. The mechanical work of writing boilerplate and translating designs into components is largely automated, but the critical thinking and stewardship still require skilled developers.</p><h2 id="ready-to-explore-how-ai-can-enhance-your-react-development">Ready to Explore How AI Can Enhance Your React Development?</h2><ul><li>Give the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-components#kendoreact-ai-components-and-features">KendoReact AI Components and Features</a> a try.</li><li>Watch demos of <a target="_blank" href="https://www.telerik.com/themebuilder">AI-powered theme generation in ThemeBuilder</a> to see how design ideation can be automated.</li><li>Try the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-tools/ai-assistant/getting-started">KendoReact MCP Server</a> to give your AI assistant deep knowledge of KendoReact components.</li><li>Check out the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-tools/ai-assistant/prompt-library">KendoReact Prompt Library</a> for ready-made prompts that target common development scenarios.</li></ul><img src="https://feeds.telerik.com/link/23056/17318469.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:bd4d6447-7473-40eb-b916-7931c305c4b7</id>
    <title type="text">Simplified Authentication with Better Auth</title>
    <summary type="text">We’ll build a complete email and password authentication system with session management to see how Better Auth works. Users will be able to sign up, log in and stay authenticated across page refreshes. We’ll use Next.js, Drizzle ORM and SQLite.</summary>
    <published>2026-04-09T17:26:49Z</published>
    <updated>2026-04-23T22:50:00Z</updated>
    <author>
      <name>Christian Nwamba </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23056/17316561/simplified-authentication-better-auth"/>
    <content type="text"><![CDATA[<p><span class="featured">We&rsquo;ll build a complete email and password authentication system with session management to see how Better Auth works. Users will be able to sign up, log in and stay authenticated across page refreshes. We&rsquo;ll use Next.js, Drizzle ORM and SQLite.</span></p><p>Authentication should be straightforward, but in practice, it takes time. You&rsquo;re dealing with sessions, cookies, password hashing, OAuth redirects and email verification, and each piece has its own quirks and scattered documentation. The whole time, you may also be asking yourself if you&rsquo;re doing this securely. One mistake exposes your users.</p><p>Most existing tools don&rsquo;t help much. <a target="_blank" href="https://next-auth.js.org/">NextAuth</a> is solid if you&rsquo;re using Next.js, but switching frameworks means starting over. Building from scratch gives you control at the cost of maintaining every security detail yourself. <a target="_blank" href="https://clerk.com/">Clerk</a> and <a target="_blank" href="https://auth0.com/">Auth0</a> work well until you reach their pricing tiers or require a feature they don&rsquo;t support. <a target="_blank" href="https://www.passportjs.org/">Passport.js</a> works, but it hasn&rsquo;t aged well&mdash;there&rsquo;s callback hell and endless boilerplate.</p><p><a target="_blank" href="https://www.better-auth.com/">Better Auth</a> takes a different approach. It&rsquo;s lightweight, works with any framework (<a target="_blank" href="https://nextjs.org/">Next.js</a>, <a target="_blank" href="https://remix.run/">Remix</a>, <a target="_blank" href="https://svelte.dev/">Svelte</a>, etc.), and comes with <a target="_blank" href="https://www.typescriptlang.org/">TypeScript</a> baked in. You get OAuth, 2FA and password resets out of the box. You can also customize when you need to, or just use the defaults.</p><p>In this guide, we&rsquo;ll build a complete email and password authentication system with session management to see how Better Auth works. Users will be able to sign up, log in and stay authenticated across page refreshes. We&rsquo;ll use Next.js, Drizzle ORM and SQLite.</p><h2 id="prerequisites">Prerequisites</h2><p>To follow along with this guide, you&rsquo;ll need:</p><ul><li>A decent understanding of JavaScript/TypeScript</li><li>Basic familiarity with React and Next.js</li><li>A database ready (<a target="_blank" href="https://www.postgresql.org/">PostgreSQL</a>, <a target="_blank" href="https://www.mysql.com/">MySQL</a> or <a target="_blank" href="https://sqlite.org/">SQLite</a>)</li></ul><h2 id="what-is-better-auth">What Is Better Auth?</h2><p>Better Auth is a TypeScript-first authentication library that avoids the usual trade-offs like vendor lock-in, expensive monthly fees or complex configurations. It is framework-agnostic, so you can use it with Next.js today and switch to Remix or SvelteKit tomorrow without rewriting your auth logic. It&rsquo;s not a managed service, so there&rsquo;s no per-user pricing or vendor lock-in.</p><p>What makes it different? It&rsquo;s database-agnostic, meaning you can use PostgreSQL, MySQL, SQLite or MongoDB. Better Auth adapts through adapters like Prisma, Drizzle and Mongoose. It&rsquo;s type-safe by default, built in TypeScript from the ground up, so your IDE knows what methods exist, what data comes back, and catches errors before you run your code. It also has security measures built in by default, with proper password hashing, HttpOnly cookies, CSRF protection and secure session management. The defaults follow best practices.</p><p>Better Auth supports OAuth providers (Google, GitHub, etc.), magic links, two-factor authentication, passkeys, even enterprise SSO, and more than what we&rsquo;ll cover in this article. We&rsquo;re focusing on the fundamentals so you understand how the system works. Once you grasp the basics, adding these features is straightforward through Better Auth&rsquo;s plugin system.</p><h2 id="project-setup">Project Setup</h2><p>Let&rsquo;s start by creating a new Next.js project with TypeScript and <a target="_blank" href="https://tailwindcss.com/">Tailwind CSS</a>. Run the following command in your terminal:</p><pre class=" language-shell"><code class="prism  language-shell">npx create-next-app@latest better-auth --ts --tailwind --eslint --app
</code></pre><p>This creates a Next.js project with TypeScript, Tailwind CSS, ESLint and App Router (the modern Next.js routing system) configured.</p><p>Run this command to navigate into the project:</p><pre class=" language-shell"><code class="prism  language-shell">cd better-auth
</code></pre><p>Run the following command to install Better Auth and its dependencies:</p><pre class=" language-shell"><code class="prism  language-shell">npm install better-auth drizzle-orm better-sqlite3 
npm install -D drizzle-kit @types/better-sqlite3
</code></pre><h2 id="database-setup">Database Setup</h2><p>Before configuring Better Auth, we need to prepare our database. We&rsquo;ll break this down into three distinct files to keep things organized:</p><ul><li><strong>Define the tables</strong>: Create the tables Better Auth needs (users, sessions, accounts, verification)</li><li><strong>Database initialization</strong>: Set up the SQLite connection and wrap it with Drizzle for type-safe queries</li><li><strong>Configure auth</strong>: Finally, we connect our database to Better Auth using the Drizzle adapter</li></ul><h3 id="define-the-tables">Define the Tables</h3><p>We need to explicitly define the tables Better Auth expects. We will add all of these to a single file. Open your <code>lib/auth-schema.ts</code> file and add the following to it:</p><p><strong>The User Table</strong><br />This stores basic user information.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token comment">//lib/auth-schema.ts</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> sqliteTable<span class="token punctuation">,</span> text<span class="token punctuation">,</span> integer <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"drizzle-orm/sqlite-core"</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token function">sqliteTable</span><span class="token punctuation">(</span><span class="token string">"user"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"id"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">primaryKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  name<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"name"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  email<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"email"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unique</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  emailVerified<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"emailVerified"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"boolean"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  image<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"image"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  createdAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"createdAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  updatedAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"updatedAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The <code>email</code> field is unique, meaning no two users can share the same email. Better Auth requires these specific fields for its internal functionality.</p><p>Notice we mark <code>name</code> and <code>email</code> as <code>notNull()</code> here. This is important because Better Auth infers its types from this schema. By making them required in the database, TypeScript will automatically force us to provide them in the sign-up form later.</p><p><strong>The Session Table</strong><br />This manages active login sessions.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token comment">//lib/auth-schema.ts</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> session <span class="token operator">=</span> <span class="token function">sqliteTable</span><span class="token punctuation">(</span><span class="token string">"session"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"id"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">primaryKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  expiresAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"expiresAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  token<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"token"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unique</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  createdAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"createdAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  updatedAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"updatedAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  ipAddress<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"ipAddress"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  userAgent<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"userAgent"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  userId<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"userId"</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">references</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> user<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Each session has a unique token and links to a user via <code>userId</code>. The <code>expiresAt</code> timestamp determines when the session becomes invalid.</p><p><strong>The Account Table</strong><br />This handles OAuth providers and stores authentication credentials.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token comment">//lib/auth-schema.ts</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> account <span class="token operator">=</span> <span class="token function">sqliteTable</span><span class="token punctuation">(</span><span class="token string">"account"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"id"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">primaryKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  accountId<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"accountId"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  providerId<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"providerId"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  userId<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"userId"</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">references</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> user<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">,</span>
  accessToken<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"accessToken"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  refreshToken<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"refreshToken"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  idToken<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"idToken"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  accessTokenExpiresAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"accessTokenExpiresAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  refreshTokenExpiresAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"refreshTokenExpiresAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  scope<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"scope"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  password<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"password"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  createdAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"createdAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  updatedAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"updatedAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The account table stores the user&rsquo;s credentials, including the password. This separation keeps the architecture flexible, allowing you to link other providers like GitHub or Google to the same user identity.</p><p><strong>Verification Table</strong><br />This stores temporary code for email verification and password resets.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">const</span> verification <span class="token operator">=</span> <span class="token function">sqliteTable</span><span class="token punctuation">(</span><span class="token string">"verification"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"id"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">primaryKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  identifier<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"identifier"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  value<span class="token punctuation">:</span> <span class="token function">text</span><span class="token punctuation">(</span><span class="token string">"value"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  expiresAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"expiresAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  createdAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"createdAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  updatedAt<span class="token punctuation">:</span> <span class="token function">integer</span><span class="token punctuation">(</span><span class="token string">"updatedAt"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token punctuation">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>This table acts as a temporary vault for security tokens. When the system sends an email to verify a user, the unique code is stored here to ensure the link is valid and hasn&rsquo;t expired when clicked.</p><h3 id="database-initialization">Database Initialization</h3><p>We need a running database connection. Let&rsquo;s create a file called <code>lib/db.ts</code>. This is where we initialize SQLite and wrap it in Drizzle so we can use it everywhere else. We wrap it because we want to write TypeScript, not SQL strings. By passing the connection to Drizzle, you get to query your database using typed methods.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token comment">// lib/db.ts </span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> drizzle <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"drizzle-orm/better-sqlite3"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> Database <span class="token keyword">from</span> <span class="token string">"better-sqlite3"</span><span class="token punctuation">;</span>

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

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

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

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

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

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

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

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

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

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

<span class="token keyword">return</span> <span class="token punctuation">(</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col gap-4 w-full max-w-md mx-auto mt-10 border border-gray-200 p-6 rounded-lg shadow-sm bg-white<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-xl font-bold text-gray-900<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Create Account<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col gap-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm font-medium text-gray-700<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
        <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span>
        <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>name<span class="token punctuation">}</span></span>
        <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setName</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
        <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>John Doe<span class="token punctuation">"</span></span>
        <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>border border-gray-300 p-2 rounded focus:outline-none focus:ring-2 focus:ring-black text-black bg-white<span class="token punctuation">"</span></span>
      <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col gap-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm font-medium text-gray-700<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Email<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
        <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span>
        <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>email<span class="token punctuation">}</span></span>
        <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setEmail</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
        <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>user@example.com<span class="token punctuation">"</span></span>
        <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>border border-gray-300 p-2 rounded focus:outline-none focus:ring-2 focus:ring-black text-black bg-white<span class="token punctuation">"</span></span>
      <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col gap-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm font-medium text-gray-700<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Password<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
        <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span>
        <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>password<span class="token punctuation">}</span></span>
        <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setPassword</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
        <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;<span class="token punctuation">"</span></span>
        <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>border border-gray-300 p-2 rounded focus:outline-none focus:ring-2 focus:ring-black text-black bg-white<span class="token punctuation">"</span></span>
      <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

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

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

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">SignIn</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>email<span class="token punctuation">,</span> setEmail<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>password<span class="token punctuation">,</span> setPassword<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>isLoading<span class="token punctuation">,</span> setIsLoading<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token function">useRouter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> signIn <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">await</span> authClient<span class="token punctuation">.</span>signIn<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span>
      <span class="token punctuation">{</span>
        email<span class="token punctuation">,</span>
        password<span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        onRequest<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token function">setIsLoading</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        onSuccess<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token function">setIsLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">"/dashboard"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        onError<span class="token punctuation">:</span> <span class="token punctuation">(</span>ctx<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token function">setIsLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token function">alert</span><span class="token punctuation">(</span>ctx<span class="token punctuation">.</span>error<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col gap-4 w-full max-w-md mx-auto mt-10 border border-gray-200 p-6 rounded-lg shadow-sm bg-white<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-xl font-bold text-gray-900<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Sign In<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>

      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col gap-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm font-medium text-gray-700<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Email<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
          <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span>
          <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>email<span class="token punctuation">}</span></span>
          <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setEmail</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
          <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>user@example.com<span class="token punctuation">"</span></span>
          <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>border border-gray-300 p-2 rounded focus:outline-none focus:ring-2 focus:ring-black text-black bg-white<span class="token punctuation">"</span></span>
        <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col gap-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm font-medium text-gray-700<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Password<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
          <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span>
          <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>password<span class="token punctuation">}</span></span>
          <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setPassword</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
          <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;<span class="token punctuation">"</span></span>
          <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>border border-gray-300 p-2 rounded focus:outline-none focus:ring-2 focus:ring-black text-black bg-white<span class="token punctuation">"</span></span>
        <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

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

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

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

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

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

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

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">authMiddleware</span><span class="token punctuation">(</span>request<span class="token punctuation">:</span> NextRequest<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> data<span class="token punctuation">:</span> session <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> betterFetch<span class="token operator">&lt;</span>Session<span class="token operator">&gt;</span><span class="token punctuation">(</span>
    <span class="token string">"/api/auth/get-session"</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      baseURL<span class="token punctuation">:</span> request<span class="token punctuation">.</span>nextUrl<span class="token punctuation">.</span>origin<span class="token punctuation">,</span>
      headers<span class="token punctuation">:</span> <span class="token punctuation">{</span>
        cookie<span class="token punctuation">:</span> request<span class="token punctuation">.</span>headers<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">"cookie"</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token string">""</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>session<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> NextResponse<span class="token punctuation">.</span><span class="token function">redirect</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">URL</span><span class="token punctuation">(</span><span class="token string">"/signin"</span><span class="token punctuation">,</span> request<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> NextResponse<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

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

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

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Dashboard</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token function">useRouter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> data<span class="token punctuation">:</span> session<span class="token punctuation">,</span> isPending <span class="token punctuation">}</span> <span class="token operator">=</span> authClient<span class="token punctuation">.</span><span class="token function">useSession</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>isPending<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex min-h-screen items-center justify-center<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-gray-500<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Loading<span class="token operator">...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col items-center justify-center min-h-screen gap-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-2xl font-bold<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Dashboard<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>p-4 border rounded shadow-sm bg-white min-w-[300px]<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-gray-600 mb-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          Signed <span class="token keyword">in</span> <span class="token keyword">as</span><span class="token punctuation">:</span><span class="token punctuation">{</span><span class="token string">" "</span><span class="token punctuation">}</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>font-semibold text-black<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token punctuation">{</span>session<span class="token operator">?</span><span class="token punctuation">.</span>user<span class="token punctuation">.</span>email<span class="token punctuation">}</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-xs text-gray-400<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>User ID<span class="token punctuation">:</span> <span class="token punctuation">{</span>session<span class="token operator">?</span><span class="token punctuation">.</span>user<span class="token punctuation">.</span>id<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

      <span class="token operator">&lt;</span>button
        onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token keyword">await</span> authClient<span class="token punctuation">.</span><span class="token function">signOut</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
            fetchOptions<span class="token punctuation">:</span> <span class="token punctuation">{</span>
              onSuccess<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
                router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">"/signin"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
              <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">}</span>
        className<span class="token operator">=</span><span class="token string">"px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600 transition"</span>
      <span class="token operator">&gt;</span>
        Sign Out
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Now when we sign out from the app and try to manually visit <a target="_blank" href="http://localhost:3000/dashboard">http://localhost:3000/dashboard</a>, we should be instantly redirected back to the sign-in page. The dashboard will never attempt to render because there&rsquo;s no valid session.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/access-the-dashboard.gif?sfvrsn=32489ceb_2" title="Trying to access the dashboard without a session" alt="Trying to access the dashboard without a session" /></p><h2 id="conclusion">Conclusion</h2><p>At the base level, Better Auth handles the heavy lifting for authentication. The good thing is you aren&rsquo;t reinventing the wheel, and because it works with pretty much everything, you don&rsquo;t even have to rewrite your whole auth setup if you switch frameworks down the line. It just works, so you can focus on your app.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">An Introduction to TanStack DB: A Reactive Data Layer for Modern Web Applications</h4></div><div class="col-8"><p class="u-fs16 u-mb0">In this article, we will build a to-do app to <a target="_blank" href="https://www.telerik.com https://www.telerik.com/blogs/introduction-tanstack-db-reactive-data-layer-modern-web-applications">see TanStack DB in action</a>. We&rsquo;ll cover how to set up collections, what &ldquo;live queries&rdquo; are, and why &ldquo;differential dataflow&rdquo; makes it so fast. We'll also cover when to use TanStack DB and when TanStack Query alone is enough.</p></div></div></aside><img src="https://feeds.telerik.com/link/23056/17316561.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:9bf61f7e-e7a4-44d4-aba4-e8c1fc74615b</id>
    <title type="text">Progress Telerik Agentic UI Generator vs. Syncfusion Agentic UI Builder</title>
    <summary type="text">See how the AI-based UI creation tools from devtools powerhouses Progress and Syncfusion stack up when they go head to head.</summary>
    <published>2026-04-08T16:38:33Z</published>
    <updated>2026-04-23T22:50:00Z</updated>
    <author>
      <name>Hassan Djirdeh </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23056/17315938/progress-telerik-agentic-ui-generator-vs-syncfusion-agentic-ui-builder"/>
    <content type="text"><![CDATA[<p><span class="featured">See how the AI-based UI creation tools from devtools powerhouses Progress and Syncfusion stack up when they go head to head. </span></p><p>AI-powered code generation has become a significant part of how developers build user interfaces. The <a target="_blank" href="https://survey.stackoverflow.co/2025/ai/#1-ai-tools-in-the-development-process">2025 Stack Overflow Developer Survey</a> found that 84% of developers are now using or planning to use AI tools in their development process.</p><p>Original AI adoption has been through tools like code autocompletion and chat-based assistants, but agentic UI tools take things further. Rather than suggesting the next line of code, they can take a natural language prompt and produce working, styled UI code in seconds.</p><p>However, not all AI generation tools are created equal. The quality of the output, how reliably it builds on the first attempt, how fast it runs and how well it handles things like accessibility and theming can vary quite a bit between tools. These differences matter because a tool that requires a large number of follow-up prompts to correct errors or produce code that doesn&rsquo;t match the original requirements isn&rsquo;t truly saving us time.</p><p>In this article, we&rsquo;ll look at a head-to-head comparison between two agentic UI generation tools: the <strong>Progress Telerik Agentic UI Generator</strong> which includes the <a target="_blank" href="https://www.telerik.com/blazor-ui/documentation/ai/agentic-ui-generator/getting-started">Blazor Agentic UI Generator for .NET/Blazor</a> and the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-tools/agentic-ui-generator/getting-started">Kendo UI Generator for Angular and React</a>, and the <a target="_blank" href="https://www.syncfusion.com/explore/agentic-ui-builder/"><strong>Syncfusion Agentic UI Builder</strong></a>. We&rsquo;ll walk through the results of extensive testing across multiple frameworks, covering output quality, performance, stability, accessibility, theming and more.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/progress-vs-syncfusion.jpg?sfvrsn=d281e72b_2" alt="Progress Telerik vs. Syncfusion" /></p><h2 id="how-the-comparison-was-conducted">How the Comparison Was Conducted</h2><p>To make this comparison as fair and thorough as possible, both tools were tested across multiple frameworks using two evaluation approaches.</p><h3 id="blazor.net">Blazor/.NET</h3><p>On the Blazor/.NET side, 23 prompts were run through the Telerik Agentic UI Generator and the Syncfusion Agentic UI Builder. These prompts ranged from simple single-component requests to complex multi-section layouts like e-commerce catalog pages and CMS admin dashboards. Each prompt&rsquo;s output was rated on a 0 to 7 scale:</p><ul><li><strong>0-1</strong>: Doesn&rsquo;t build or crashes with no UI</li><li><strong>2-3</strong>: Partially renders, major sections broken</li><li><strong>4</strong>: Renders but requires multiple prompts to clear build or runtime errors</li><li><strong>5</strong>: Renders but doesn&rsquo;t match prompt requirements in several areas</li><li><strong>6</strong>: Mostly complete, minor issues</li><li><strong>7</strong>: Fully matches requirements</li></ul><p>The evaluation also tracked how many prompts were needed before the output could successfully build and render, as well as the time (in seconds) from initial prompt submission to output generation.</p><h3 id="angular-and-react">Angular and React</h3><p>For Angular and React, a dedicated evaluation was conducted comparing the Kendo Agentic UI Generator against the Syncfusion Agentic UI Builder. Rather than scoring individual prompts, this evaluation focused on a technical comparison of the tools themselves. By running many prompts and examining the context returned by each tool, the analysis compared how each MCP server helps the AI agent arrive at its output across categories like layout, styling, accessibility, documentation and component handling.</p><h2 id="output-quality-and-reliability">Output Quality and Reliability</h2><p>This is the category where the gap between the two tools becomes immediately clear.</p><p>Across the 23 Blazor prompts, the Telerik Agentic UI Generator consistently produced complete, requirement-matching output on the first attempt. The Syncfusion Agentic UI Builder told a different story. It experienced <strong>five failures</strong> where no usable UI was generated at all, and several other prompts that required follow-up prompts to fix errors before the output could even build. Let&rsquo;s look at a couple of examples.</p><h3 id="failures">Failures</h3><p>The very first prompt asked both tools to build a login screen with email/password validation and an admin dashboard with a sidebar menu, key metrics and recent activity.</p><p><strong>Prompt</strong>: <em>&ldquo;I have created an empty application that now needs a login screen and an admin dashboard. Add a login form with email/password fields and validation. After a successful login, redirect to an admin dashboard page featuring a sidebar menu and a main content area displaying key metrics and recent activity.&rdquo;</em></p><p>The Telerik Generator produced a fully working output on the first attempt.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/blazor-agentic-ui-prompt-1.png?sfvrsn=ead93eba_1" alt="Telerik UI Generator produced dashboard" /></p><p>The Syncfusion Builder returned an error along the lines of: <code>Error. This response is truncated because it is too long. Try rephrasing your question.</code> No UI was generated at all.</p><p>The second prompt told both tools to create a monitoring dashboard with system health KPIs, a log stream panel, charts for API response times and requests per service.</p><p><strong>Prompt</strong>: <em>&ldquo;Create a new page using the existing top navigation and footer. In the middle, add 3 rows with 3 responsive columns each. The top row shows system health KPIs for CPU, memory and error counts. The middle rows include a Log Stream panel, a line Chart of API response times and a bar chart of requests per service. The bottom row contains a Deployment History table, an Alerts panel and a list of open tickets.&rdquo;</em></p><p>The Telerik Generator again produced a fully working output on the first pass.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/blazor-agentic-ui-prompt-2.png?sfvrsn=150ecc0b_1" alt="Telerik Generator produced dashboard with graphs" /></p><p>The Syncfusion Builder hit the same truncation error.</p><p>These are the kinds of prompts that represent real-world use cases. A login screen with a dashboard and a monitoring page with multiple data panels aren&rsquo;t unusual requests.</p><h3 id="errors-requiring-follow-ups">Errors Requiring Follow-ups</h3><p>Not every issue is an error during the generation process. Some prompts produced output that needed additional work to get running.</p><p>We fired a prompt to ask for a product catalog page with a responsive layout, product cards, a filtering toolbar and expandable detail views. The Telerik Generator handled it cleanly on the first attempt. The Syncfusion Builder hit an error about a missing component parameter and needed a second follow-up prompt to fix it.</p><p><strong>Prompt</strong>: <em>&ldquo;Create a product catalog page with a responsive CSS layout. The layout should display product cards. Add a toolbar with filtering options, and expandable detail view for each product that work seamlessly on mobile, tablet, and desktop.&rdquo;</em></p><p>The first output by the Telerik Blazor generator:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/blazor-agentic-ui-prompt-4.png?sfvrsn=5b3d958b_1" alt="Telerik Blazor AI UI Generator produced product catalog" /></p><p>The final output from Syncfusion, after the necessary follow-up prompt:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/syncfusion-agentic-ui-prompt-4.png?sfvrsn=a91f64f0_1" alt="Syncfusion product catalog" /></p><p>The Syncfusion Builder&rsquo;s errors in these cases often involved referencing component parameters that don&rsquo;t exist, which may suggest the tool&rsquo;s AI agent is working with less reliable component information during generation.</p><h3 id="partial-results">Partial Results</h3><p>Not all issues showed up as crashes or errors needing follow-ups. Let&rsquo;s look at an example of a prompt that was made which involved a theming request.</p><p><strong>Prompt</strong>: <em>&ldquo;Generate a custom theme for a corporate blue and green color scheme with high contrast accessibility requirements.&rdquo;</em></p><p>The Telerik Agentic UI Generator created the output matching the requirements.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/blazor-agentic-ui-prompt-13.png?sfvrsn=ed53d11a_1" alt="Telerik Agentic UI generator blue n=and green" /></p><p>The Syncfusion Builder did create a custom theme, but the expected theme wasn&rsquo;t applied to the output.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/syncfusion-agentic-ui-prompt-13.png?sfvrsn=eaac1328_1" alt="Syncfusion green and blue missing" /></p><h3 id="the-bigger-picture">The Bigger Picture</h3><p>Even when we set aside the failures and only look at prompts where the Syncfusion Builder produced something usable, the outputs still frequently fell short of the original requirements.</p><p>On the Angular and React side, the findings were consistent. While the final rendered UI sometimes appeared similar at a glance, the most significant differences were in how each tool&rsquo;s MCP server helped the agent arrive at that output. The Kendo Generator&rsquo;s tools consistently delivered more relevant, targeted context to the AI agent, filtering results to what was actually needed for the prompt. The Syncfusion Builder&rsquo;s tools returned broader, less filtered responses, often including full component prop lists and governance rules regardless of what was asked.</p><h2 id="performance">Performance</h2><p>Speed matters when we&rsquo;re iterating on UI designs with AI. Waiting several minutes for a complex layout to generate can significantly slow down the development flow.</p><p>Across the Blazor evaluation, the Telerik Generator was consistently faster. The speed advantage was most noticeable on complex layout prompts. For example, on a complex e-commerce catalog page with filtering, sorting, responsive breakpoints and pagination, the Telerik Generator completed in about 799 seconds while the Syncfusion Builder took 908 seconds.</p><p>There was one outlier where Syncfusion was notably faster (a simpler single-component case), but across the full set of 23 prompts, the speed advantage consistently favored Telerik.</p><h2 id="accessibility">Accessibility</h2><p>Accessibility is often treated as an afterthought, but for enterprise applications, it&rsquo;s a requirement, not a nice-to-have!</p><p>The Kendo Generator includes a dedicated accessibility tool (<a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-tools/agentic-ui-generator/prompt-library#accessibility-assistant">#kendo_accessibility_assistant</a>) that retrieves WCAG 2.2 Level AA guidelines as a mandatory step in the generation process. It also fetches component-specific accessibility requirements for each component used in the output. This leads to every piece of generated UI having accessibility considerations baked in from the start.</p><p>From what we can gather, and at the time of writing, the Syncfusion Builder doesn&rsquo;t have a strong accessibility tool like the <code>#kendo_accessibility_assistant</code>.</p><h2 id="theming-layout-and-documentation">Theming, Layout and Documentation</h2><p>Beyond output quality and speed, the Angular and React evaluation revealed some important architectural differences in how each tool handles theming, layout and documentation.</p><h3 id="theming">Theming</h3><p><strong>Theming</strong> is more than color selection. The Kendo UI Generator produces a complete design system from a single prompt, including colors, typography, spacing scales, border radius, elevation and shadows. The Syncfusion Builder&rsquo;s style tool is limited to component state colors and semantic colors. Typography, spacing and elevation aren&rsquo;t reachable through it, so the generated output may look right in terms of color but lack the design coherence that holds a full application together.</p><h3 id="layout">Layout</h3><p><strong>Layout</strong> is also where a notable dependency difference comes in. The Kendo UI Generator uses a self-contained layout system built on its own CSS utilities, introducing no external dependencies. The Syncfusion Builder relies on <a target="_blank" href="https://tailwindcss.com/">Tailwind CSS</a>, injected into every project, and works from a catalog of 265+ prebuilt blocks. When the desired layout doesn&rsquo;t match a catalog entry, the result approximates what was asked for.</p><p>For teams already using Tailwind, this might feel natural but for projects on a different CSS framework (<a target="_blank" href="https://material.angular.dev/">Angular Material</a>, for example), adding Tailwind on top can introduce style conflicts. This can also be a potential blocker for organizations that restrict third-party dependencies.</p><p>Responsiveness follows a similar split: the Kendo UI Generator has a dedicated phase with explicit breakpoint reasoning, while the Syncfusion Builder inherits responsive behavior from Tailwind&rsquo;s defaults without any first-class responsive logic of its own.</p><h3 id="documentation">Documentation</h3><p><strong>Documentation</strong> plays a bigger role in output quality than it might seem, since it directly shapes how well the AI agent understands the components it&rsquo;s generating. The Kendo UI Generator injects relevant documentation chunks directly into every component tool call, including API references with full type signatures. The Syncfusion Builder treats documentation as a separate tool, triggered only by specific keywords. At the time of the evaluation, results from this tool were inconsistent and the service had been unavailable for over 24 hours for both Angular and React.</p><p>One other important observation from the Angular and React evaluation: the Kendo UI Generator customizes its workflow per prompt using confidence scores, including only the tools and instructions relevant to each request. The Syncfusion Builder runs the same fixed sequence for most prompts regardless of complexity, and its component tools return the full prop list and approximately 250 lines of governance rules on every call. The result is that <strong>the Kendo UI agent operates on targeted, preprocessed context while the Syncfusion agent carries a heavier payload for every request</strong>.</p><h2 id="wrap-up">Wrap-up</h2><p>The comparison across Blazor, Angular and React tells a consistent story with these agentic UI generators. The Progress Telerik Agentic UI Generator outperforms the Syncfusion Agentic UI Builder across output quality, reliability, performance, accessibility, theming, layout and documentation.</p><p>On the Blazor side, the Telerik Generator had zero full failures across 23 prompts while Syncfusion had five, along with a consistent speed advantage on complex prompts and more reliable first-pass output. On the Angular and React side, the advantages show up in the underlying architecture, where the Kendo Generator&rsquo;s tools consistently deliver cleaner, more relevant context to the AI agent.</p><hr /><blockquote><p>Get started with AI-empowered development. The <a target="_blank" href="https://www.telerik.com/mcp-servers">Kendo UI and Telerik AI tools</a> are ready. And they come as part of the free trial of the component libraries.</p><br /><p><a href="https://www.telerik.com/mcp-servers#how-to-try" class="Btn" target="_blank">Try Now</a></p></blockquote><hr /><p>For more information on the Progress Telerik Agentic UI Generator, check out the following resources:</p><ul><li><a target="_blank" href="https://www.telerik.com/blazor-ui/documentation/ai/agentic-ui-generator/getting-started">Telerik Agentic UI Generator for Blazor</a></li><li><a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/agentic-ui-generator/getting-started">Kendo UI Generator for Angular</a></li><li><a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-tools/agentic-ui-generator/getting-started">Kendo UI Generator for React</a></li></ul><p>The full comparison data referenced in this article is available for download:</p><ul><li><a target="_blank" href="https://www.telerik.com/docs/default-source/blogs-docs//syncfusion-builder-vs-telerik-generator-comparison.xlsx">Telerik UI for Blazor Agentic UI Generator vs Syncfusion Agentic UI Builder Comparative Evaluation (XLSX)</a></li><li><a target="_blank" href="https://www.telerik.com/docs/default-source/blogs-docs//syncfusion-ui-builder-vs-kendo-ui-generator.xlsx">Kendo Agentic UI Generator vs Syncfusion Agentic UI Builder (XLSX)</a></li></ul><hr /><h2 id="summary-faqs">Summary FAQs</h2><h3 id="what-do-these-tools-do">What Do These Tools Do?</h3><h4 id="what-telerik-agentic-ui-generator-is">What Telerik Agentic UI Generator Is</h4><p>According to the <a href="https://www.telerik.com/mcp-servers" target="_blank">Progress Telerik website</a>, the Telerik Agentic UI Generator for Telerik and Kendo UI libraries is an intelligent development tool delivered through the Model Context Protocol (MCP) Server that enables UI generation from natural language prompts. Once configured and authenticated, you can use the Agentic UI Generator tool (#telerik_ui_generator) together with the available specialized MCP assistants.</p><h4 id="what-syncfusion-agentic-ui-builder-is">What Syncfusion Agentic UI Builder Is</h4><p>According to the <a target="_blank" href="https://www.syncfusion.com/explore/agentic-ui-builder/">Syncfusion site</a>, Syncfusion&rsquo;s Agentic UI Builder is designed to work inside an IDE to generate UIs, dashboards or pages with Syncfusion components with natural language commands. Syncfusion uses MCP integration to access component APIs, prebuilt UI blocks, styling configurations, icon libraries and code generation.</p><h3 id="why-does-mcp-matter-in-both-products">Why Does MCP Matter in Both Products?</h3><p>Both brands&rsquo; tools use Model Context Protocol (MCP) servers to connect AI applications directly to the software specs for the individual library. This means that the AI is informed on component documentation, best practices, workflows and tooling provided by the UI library, so the AI can create a user interface more in line with how the library was designed to work. It should result in better outputs than if an AI were cobbling together an interface without guidance.</p><p>Learn more about the individual MCP servers:</p><ul><li><a href="https://www.telerik.com/blazor-mcp-servers" target="_blank">Telerik UI for Blazor MCP Servers</a></li><li><a href="https://www.telerik.com/angular-mcp-servers" target="_blank">Kendo UI for Angular MCP Servers</a></li><li><a href="https://www.telerik.com/react-mcp-servers" target="_blank">KendoReact MCP Servers</a></li><li><a target="_blank" href="https://ej2.syncfusion.com/react/documentation/mcp-server/overview">Syncfusion EJ2 React MCP Server</a></li><li><a target="_blank" href="https://ej2.syncfusion.com/angular/documentation/mcp-server/overview">Syncfusion EJ2 Angular MCP Server</a></li><li><a target="_blank" href="https://blazor.syncfusion.com/documentation/mcp-server/overview">Syncfusion Blazor MCP Server</a></li></ul><h3 id="are-prompt-libraries-included">Are Prompt Libraries Included?</h3><h4 id="telerik-and-kendo-ui-generator-prompt-libraries">Telerik and Kendo UI Generator Prompt Libraries</h4><p>Yes! Prompt libraries are included for the Kendo UI and Telerik AI UI Generator tools:</p><ul><li>Blazor: <a target="_blank" href="https://www.telerik.com/blazor-ui/documentation/ai/agentic-ui-generator/prompt-library">https://www.telerik.com/blazor-ui/documentation/ai/agentic-ui-generator/prompt-library</a></li><li>React: <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-tools/agentic-ui-generator/getting-started">https://www.telerik.com/kendo-react-ui/components/ai-tools/agentic-ui-generator/getting-started</a></li><li>Angular: <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/agentic-ui-generator/prompt-library">https://www.telerik.com/kendo-angular-ui/components/ai-tools/agentic-ui-generator/prompt-library</a></li></ul><h4 id="syncfusion-agentic-ui-builder-prompt-libraries">Syncfusion Agentic UI Builder Prompt Libraries</h4><p>Yes! Prompt libraries are included for the Syncfusion Agentic UI Builder tools:</p><ul><li>Blazor: <a target="_blank" href="https://blazor.syncfusion.com/documentation/mcp-server/agentic-ui-builder/prompt-library">https://blazor.syncfusion.com/documentation/mcp-server/agentic-ui-builder/prompt-library</a></li><li>React: <a target="_blank" href="https://ej2.syncfusion.com/react/documentation/mcp-server/agentic-ui-builder/prompt-library">https://ej2.syncfusion.com/react/documentation/mcp-server/agentic-ui-builder/prompt-library</a></li><li>Angular: <a target="_blank" href="https://ej2.syncfusion.com/angular/documentation/mcp-server/agentic-ui-builder/prompt-library">https://ej2.syncfusion.com/angular/documentation/mcp-server/agentic-ui-builder/prompt-library</a></li></ul><img src="https://feeds.telerik.com/link/23056/17315938.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:4733c0a3-bf88-4efb-8d20-246db8da5688</id>
    <title type="text">The Great React Grid-Off: KendoReact vs. MUI vs. AG Grid</title>
    <summary type="text">Curious how the best React grids on the market compete head-to-head? KendoReact vs. MUI vs. AG Grid—let’s see it!</summary>
    <published>2026-03-19T20:15:24Z</published>
    <updated>2026-04-23T22:50:00Z</updated>
    <author>
      <name>Kathryn Grayson Nanz </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23056/17302239/great-react-grid-off-kendoreact-vs-mui-vs-ag-grid"/>
    <content type="text"><![CDATA[<p><span class="featured">Curious how the best React grids on the market compete head-to-head? KendoReact vs. MUI vs. AG Grid&mdash;let&rsquo;s see it!</span></p><p>If you&rsquo;re looking for an enterprise-level <a href="https://www.telerik.com/kendo-react-ui/components/grid" target="_blank">data grid for your React</a> application, there&rsquo;s no shortage of options to consider. When you&rsquo;re making a comparison, many aspects will be subjective; those things will ultimately come down to which approach makes the most sense to you as a developer and what you think will be easiest for your existing team to adopt.</p><p>However, there are also performance-related metrics that are objective, which we can test directly and draw clear conclusions around. In the hopes of making that task slightly easier for you, we ran the tests ourselves and would like to share the results.</p><p>This benchmark compares the rendering and virtualization performance of three popular React data grids: Progress KendoReact, MUI and AG Grid. The goal is to provide objective, repeatable performance data across common real-world scenarios&mdash;from small datasets to large, virtualized grids with up to 1 million rows. We wanted to mirror production-like situations as closely as possible, rather than simply testing demo scenarios that aren&rsquo;t commonly reflected in real applications.</p><h2 id="sneak-peek-at-the-results">Sneak Peek at the Results</h2><p>For those of you who are just eager to see our conclusions, below is a summary of our results. For those interested in diving deeper into the methodology and details, read on!</p><ul><li>For basic grids (&le;5k rows, no virtualization), MUI is faster.</li><li>When paging is enabled, the KendoReact consistently leads.</li><li>If virtualization is needed (10k&ndash;1M rows), KendoReact is significantly faster, with performance gaps widening as datasets grow.</li><li>In situations with row <em>and</em> column virtualization, MUI performs well on smaller datasets, while KendoReact scales better at higher volumes.</li><li>If you&rsquo;re working with very large datasets, the best choice is the KendoReact Data Grid.</li></ul><h2 id="how-we-measure-performance">How We Measure Performance</h2><p>Before we look at the numbers, let&rsquo;s take a second to discuss how we calculated them.</p><p>We run automated performance tests twice each week (for our own visibility) and track the results to a set of internal dashboards. This is for our own learning&mdash;we want to keep an eye on our grid and how it performs in real-world scenarios, as compared to our competitors. All our tests are designed to be repeatable and to reflect realistic application usage.</p><p>We run our tests via GitHub Actions, using Selenium WebDriver and a custom browser automation in a headless Chromium browser. The tests use realistic, production-like data generated with the Faker.js library (ours is for a &ldquo;warehouse,&rdquo; with columns for ID, name, price, start date, units in stock, discontinued status and a description). For tests requiring wider datasets, additional column content is dynamically generated, with each cell containing realistic five-character alphanumeric data. Each scenario is executed eight times, and we average the results for consistency.</p><p>The testing framework uses high-precision millisecond timing, moving through the following steps:</p><ol><li><strong>Pre-render State:</strong> To begin, the Grid component is <em>not</em> initially loaded on the page.</li><li><strong>Data Generation:</strong> Test data is generated and prepared in memory before timing begins.</li><li><strong>Timer Start:</strong> A precise timestamp is captured using <code>Date.now()</code> immediately before grid initialization.</li><li><strong>Grid Load:</strong> The Grid component is rendered with a full dataset.</li><li><strong>Completion Detection:</strong> Automated polling (every 10ms) detects when the last table cell becomes visible in the DOM using XPath selectors (<code>td[contains(@class,'k-table-td')]</code>).</li><li><strong>Timer Stop:</strong> A timestamp is captured when the target cell is detected.</li><li><strong>Result:</strong> The rendering time in milliseconds is logged.</li></ol><h2 id="what-gets-measured">What Gets Measured</h2><p>We look at our KendoReact Data Grid (Premium) as compared to AG Grid (Community Edition) and MUI Grid (Material-UI Data Grid) in terms of pure component rendering time, DOM manipulation performance, virtual scrolling efficiency and template rendering overhead. We do not measure network latency, API calls or data generation time.</p><p>For all the grids, we test in four different configurations:</p><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 <tr><th style="width:25%;padding:5px;"><strong>Scenario</strong></th><th style="width:25%;padding:5px;"><strong>Rows</strong></th><th style="width:25%;padding:5px;"><strong>Columns</strong></th><th style="width:25%;padding:5px;"><strong>Features</strong></th></tr></thead><tbody><tr><td style="width:25%;padding:5px;"><strong>Basic Grid (no virtualization)</strong></td><td style="width:25%;padding:5px;">5,000</td><td style="width:25%;padding:5px;">20</td><td style="width:25%;padding:5px;">Sorting and Filtering</td></tr><tr><td style="width:25%;padding:5px;"><strong>Paged Grid (no virtualization)</strong></td><td style="width:25%;padding:5px;">5,000</td><td style="width:25%;padding:5px;">20</td><td style="width:25%;padding:5px;">Sorting, Filtering, Paging</td></tr><tr><td style="width:25%;padding:5px;"><strong>Row Virtualization</strong></td><td style="width:25%;padding:5px;">1,000,000</td><td style="width:25%;padding:5px;">10</td><td style="width:25%;padding:5px;">Sorting, Filtering, Row Virtualization</td></tr><tr><td style="width:25%;padding:5px;"><strong>Row + Column Virtualization</strong></td><td style="width:25%;padding:5px;">100,000</td><td style="width:25%;padding:5px;">100</td><td style="width:25%;padding:5px;">Sorting, Filtering, Dual-Axis Virtualization</td></tr></tbody></table><br /><h2 id="the-results-in-detail">The Results in Detail</h2><p>Now that the scope and scale of the tests have been established, let&rsquo;s look at the results. This particular benchmark compared KendoReact v13.0.0 against AG Grid Community v34.3.1 and MUI Grid v8.11.0. <strong>Below are the results from this specific test, but it&rsquo;s worth noting that we repeat these tests regularly and the results are consistently similar.</strong></p><h3 id="grid-basic-tests">Grid Basic Tests</h3><h4 id="rows-x-10-cols">100 Rows x 10 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><style>table,
 th,
        td {
            border: 1px;
            border-color: #bdbdba;
            border-style: dotted;
            border-collapse: collapse;
            margin-right: auto;
            text-align: left;
        }
    </style>
 <thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>MUI</td><td>671.00ms</td></tr><tr><td>KendoReact</td><td>709.00ms</td></tr><tr><td>AG Grid</td><td>841.25ms</td></tr></tbody></table><br /><h4 id="rows-x-100-cols">100 Rows x 100 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>MUI</td><td>1762.88ms</td></tr><tr><td>AG Grid</td><td>1817ms</td></tr><tr><td>KendoReact</td><td>1998.00ms</td></tr></tbody></table><br /><h4 id="rows-x-10-cols-1">1,000 Rows x 10 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>AG Grid</td><td>2133.63ms</td></tr><tr><td>MUI</td><td>2364.25ms</td></tr><tr><td>KendoReact</td><td>2475.88ms</td></tr></tbody></table><br /><h4 id="rows-x-20-cols">5,000 Rows x 20 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>MUI</td><td>104004.25ms</td></tr><tr><td>KendoReact</td><td>14718.25ms</td></tr><tr><td>AG Grid</td><td>16494.63ms</td></tr></tbody></table><br /><h3 id="grid-paging-tests">Grid Paging Tests</h3><h4 id="rows-x-10-cols-2">100 Rows x 10 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>KendoReact</td><td>332.25ms</td></tr><tr><td>MUI</td><td>413.88ms</td></tr><tr><td>AG Grid</td><td>459.50ms</td></tr></tbody></table><br /><h4 id="rows-x-100-cols-1">100 Rows x 100 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>KendoReact</td><td>824.13ms</td></tr><tr><td>AG Grid</td><td>846.00ms</td></tr><tr><td>MUI</td><td>988.88ms</td></tr></tbody></table><br /><h4 id="rows-x-10-cols-3">1,000 Rows x 10 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>KendoReact</td><td>335.63ms</td></tr><tr><td>MUI</td><td>424.38ms</td></tr><tr><td>AG Grid</td><td>448.63ms</td></tr></tbody></table><br /><h4 id="rows-x-20-cols-1">5,000 Rows x 20 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>KendoReact</td><td>374.88ms</td></tr><tr><td>MUI</td><td>462.38ms</td></tr><tr><td>AG Grid</td><td>494.75ms</td></tr></tbody></table><br /><h3 id="column-virtualization-tests">Column Virtualization Tests</h3><h4 id="rows-x-100-cols-2">10,000 Rows x 100 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>MUI</td><td>489.13ms</td></tr><tr><td>AG Grid</td><td>495.88ms</td></tr><tr><td>KendoReact</td><td>763.25ms</td></tr></tbody></table><br /><h4 id="rows-x-100-cols-3">100,000 Rows x 100 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>KendoReact</td><td>621.25ms</td></tr><tr><td>AG Grid</td><td>847.75ms</td></tr><tr><td>MUI</td><td>1079.88ms</td></tr></tbody></table><br /><h3 id="dual-axis-virtualization-tests">Dual-Axis Virtualization Tests</h3><h4 id="rows-x-10-cols-4">10,000 Rows x 10 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>KendoReact</td><td>319.25ms</td></tr><tr><td>MUI</td><td>419.50ms</td></tr><tr><td>AG Grid</td><td>601.25ms</td></tr></tbody></table><br /><h4 id="rows-x-10-cols-5">100,000 Rows x 10 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>KendoReact</td><td>350.75ms</td></tr><tr><td>MUI</td><td>705.38ms</td></tr><tr><td>AG Grid</td><td>798.75ms</td></tr></tbody></table><br /><h4 id="rows-x-10-cols-6">1,000,000 Rows x 10 Cols</h4><table cellspacing="5" style="text-align:left;margin-right:auto;"><thead><style>table,
 th,
            td {
                border: 1px;
                border-color: #bdbdba;
                border-style: dotted;
                border-collapse: collapse;
                margin-right: auto;
                text-align: left;
            }
        </style>
 </thead><thead><tr><th>Vendor</th><th>Performance Time</th></tr></thead><tbody><tr style="width:50%;background-color:#ffff35;"><td>KendoReact</td><td>826.63ms</td></tr><tr><td>MUI</td><td>5608.38ms</td></tr><tr><td>AG Grid</td><td>5974.25ms</td></tr></tbody></table><br /><h3 id="basic-grid">Basic Grid</h3><p>For the Basic Grid, MUI came out on top&mdash;although, it&rsquo;s worth remembering that in all these situations, we&rsquo;re talking about a matter of milliseconds (note that I&rsquo;ve converted the results into seconds in these summaries, since that&rsquo;s a bit easier to mentally parse). Still, they consistently clocked in faster than both KendoReact and AG Grid.</p><p>For a 100x10 grid, MUI (0.67s) was faster than KendoReact (0.71s) and AG Grid (0.85s). Even at 5,000x20, MUI (10.4s) still kept the lead over both KendoReact (14.7s) and AG Grid (16.5s).</p><p><strong>For small datasets without virtualization, MUI Grid shows slightly faster initial render times, though all three grids perform within the same order of magnitude.</strong></p><h3 id="paging">Paging</h3><p>The situation changes once other, more complicated factors are included. When we enable paging, we see KendoReact move into the lead.</p><p>In a 100x10 grid, KendoReact (0.33s) is faster than MUI (0.41s) and AG Grid (0.46s). Scaled up to a 5,000x20 grid, KendoReact (0.38s) still has the edge on MUI (0.46s), which in turn beats out AG Grid (0.50s).</p><p><strong>Once paging is enabled, the KendoReact Grid consistently outperforms both MUI Grid and AG Grid across all tested dataset sizes.</strong></p><h3 id="row-virtualization">Row Virtualization</h3><p>Similarly, KendoReact remains on top for row virtualization. For a 10,000x10 grid, KendoReact (0.32s) is more performant than both MUI (0.42s) and AG Grid (0.60s).</p><p>Push that to 1,000,000x10, and we start to see a truly significant difference: KendoReact (0.83s) is significantly faster than MUI (5.6s) and AG Grid (6s). Obviously, that&rsquo;s a testing scenario that pushes the boundaries of capability, but it demonstrates the kind of compounding performance costs that developers need to be aware of when dealing with larger datasets.</p><p><strong>As dataset size increases, performance gaps widen significantly. At 1,000,000 rows, KendoReact renders in under 1 second, while MUI Grid and AG Grid require more than 5 seconds.</strong></p><h3 id="row--column-virtualization">Row + Column Virtualization</h3><p>MUI and KendoReact split the victory on Row + Column Virtualization.</p><p>When we tested with a smaller dataset, MUI takes the lead: at 10,000x100, MUI (0.49s) is faster than AG Grid (0.5s), which is faster than KendoReact (0.77s).</p><p>However, KendoReact takes the crown when tested with the larger dataset: at 100,000x100, KendoReact (0.62s) beats AG Grid (0.85s) and MUI (1.1s).</p><p><strong>KendoReact scales more predictably as both row and column counts grow, avoiding compounding render costs.</strong></p><h2 id="which-grid-is-best-for-your-team">Which Grid Is Best for Your Team?</h2><p>There&rsquo;s a long-running joke: no matter what they&rsquo;re asked, a senior developer never says &ldquo;yes&rdquo; or &ldquo;no&rdquo; They always say: &ldquo;It depends.&rdquo;</p><p>I must be showing my true colors here, because when faced with the question of which grid to pick, I find myself saying &hellip; well, it depends!</p><p><strong>You might prefer MUI Grid if:</strong></p><ul><li>Your datasets are small</li><li>You prioritize Material UI consistency</li><li>You rarely rely on virtualization</li></ul><p><strong>You might prefer KendoReact Grid if:</strong></p><ul><li>Your app handles large or growing datasets</li><li>Virtualization and performance are top priorities</li><li>You need predictable enterprise-grade performance at scale</li></ul><p>If you just need basic grid functionality, all the grids we looked at here were honestly pretty evenly matched in terms of performance.</p><p>In this case, as a tech lead, I would default to other determining factors to help tip the scales. What other components are included in the library that could be leveraged in our app? How does it meet the needs of our users who rely on accessibility functionality? How customizable is it? How easy is it to integrate AI-related functionality? How often is it updated, and what are the available customer support offerings?</p><p>How you weigh and compare the answers to these questions will ultimately come down to what factors are most important for both the userbase of your specific application and the needs of your specific team.</p><p>However, if you&rsquo;re dealing with truly large datasets and virtualization is a high priority, then KendoReact is the frontrunner. And the larger the dataset gets, the greater the disparity between KendoReact and the competitors.</p><p>If your application needs to handle truly large amounts of data, there&rsquo;s one grid that&rsquo;s simply better equipped to do so: the KendoReact Data Grid.</p><h2 id="try-it-yourself">Try It Yourself!</h2><p>Of course, we highly encourage you to try this experiment for yourself! That&rsquo;s why we shared our methodology: this is meant to be repeatable and standardized. If you run these tests and see different results, please let us know.</p><p>You can even try the full KendoReact library free for 30 days:</p><p><a target="_blank" href="https://www.telerik.com/try/kendo-react-ui" class="Btn">Try KendoReact</a></p><img src="https://feeds.telerik.com/link/23056/17302239.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:8fed6f1e-c388-43cd-bda2-ec55eced7d62</id>
    <title type="text">An Introduction to TanStack DB: A Reactive Data Layer for Modern Web Applications</title>
    <summary type="text">In this article, we will build a to-do app to see TanStack DB in action. We’ll cover how to set up collections, what “live queries” are, and why “differential dataflow” makes it so fast. We'll also cover when to use TanStack DB and when TanStack Query alone is enough.</summary>
    <published>2026-03-03T16:00:04Z</published>
    <updated>2026-04-23T22:50:00Z</updated>
    <author>
      <name>Christian Nwamba </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23056/17288834/introduction-tanstack-db-reactive-data-layer-modern-web-applications"/>
    <content type="text"><![CDATA[<p><span class="featured">In this article, we will build a to-do app to see TanStack DB in action. We&rsquo;ll cover how to set up collections, what &ldquo;live queries&rdquo; are, and why &ldquo;differential dataflow&rdquo; makes it so fast. We'll also cover when to use TanStack DB and when TanStack Query alone is enough.</span></p><p><a target="_blank" href="https://tanstack.com/query/latest">TanStack Query</a> is a popular library for developers to manage server data in <a target="_blank" href="https://react.dev/">React</a> applications. While it excels at fetching and caching data, it has one fundamental limitation: it treats all data as independent key-value pairs.</p><p>For example, TanStack Query doesn&rsquo;t understand that your <code>['todos']</code> data is related to your <code>['categories']</code> data. When you need to show &ldquo;all todos in the Work category,&rdquo; you&rsquo;re forced to write messy, manual <code>.filter()</code> and <code>.find()</code> logic and cross-reference data inside your components.</p><p>This is the exact problem <a target="_blank" href="https://tanstack.com/db/latest">TanStack DB</a> solves. It&rsquo;s not a replacement for TanStack Query; it&rsquo;s a new layer that enhances it. TanStack Query still handles all server communication (fetching, caching, revalidation), but it feeds that data into a high-performance, local, queryable database with proper relationships.</p><p>Instead of filtering arrays manually, your components query the local database using a structured query. The result is cleaner components, better performance and automatic reactivity when data changes.</p><p>In this article, we&rsquo;ll build a to-do app to see it in action. We&rsquo;ll see how to set up the collection, what &ldquo;live queries&rdquo; are, and why &ldquo;differential dataflow&rdquo; makes it so fast. We&rsquo;ll also cover when you should actually reach for this and when you&rsquo;re better off just sticking with plain TanStack Query.</p><h2 id="evolution-of-data-fetching-in-react">Evolution of Data Fetching in React</h2><p>To understand why TanStack DB is a big deal, it helps to look at different ways developers have tried to handle data fetching in React.</p><h3 id="the-useeffecthook">The useEffectHook</h3><p>If you&rsquo;ve been building React for a while, you&rsquo;ve seen <code>useEffect</code> used for data fetching everywhere. A typical pattern looks like this:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">function</span> <span class="token function">TodoList</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>todos<span class="token punctuation">,</span> setTodos<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>loading<span class="token punctuation">,</span> setLoading<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>error<span class="token punctuation">,</span> setError<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'/api/todos'</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>res <span class="token operator">=&gt;</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>data <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token function">setTodos</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token function">setError</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>loading<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span>Loading<span class="token operator">...</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span>Error<span class="token operator">!</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span><span class="token punctuation">{</span><span class="token comment">/* render todos */</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>This pattern was everywhere, and it worked, but it had serious problems. Every component mount triggered a data fetch since there was no caching. You had to manually track loading and error states every single time. Once you fetched the data, it just sat there getting stale with no background updates, and if two components needed the same data, they&rsquo;d fetch it separately.</p><h2 id="tanstack-query-react-query">Tanstack Query (React Query)</h2><p>TanStack Query solved these problems by abstracting away the complexity of data fetching.</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">function</span> <span class="token function">TodoList</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> data<span class="token punctuation">:</span> todos<span class="token punctuation">,</span> isLoading<span class="token punctuation">,</span> error <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useQuery</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    queryKey<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'todos'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    queryFn<span class="token punctuation">:</span> fetchTodos
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>isLoading<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span>Loading<span class="token operator">...</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span>Error<span class="token operator">!</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span><span class="token punctuation">{</span><span class="token comment">/* render todos */</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>The code snippet above is way cleaner, right? TanStack Query came with powerful features like automatic caching that lets you fetch once and use everywhere, background refetching that keeps data fresh automatically, built-in loading and error states, request deduplication so multiple components only fetch once, and stale-while-revalidate patterns. TanStack Query basically solved the &ldquo;fetching from APIs&rdquo; problem.</p><p>Despite all these perks, there&rsquo;s still a problem. The thing with TanStack Query is that it&rsquo;s great at getting data, but once that data arrives, it treats everything as separate entities&mdash;no relationships.</p><p>Imagine we&rsquo;re building a to-do app with categories. We fetch todos, we fetch categories. Both queries work perfectly. But what if we want to show &ldquo;all uncompleted Work todos,&rdquo; how do we do it?</p><p>We&rsquo;d end up writing something like this:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> data<span class="token punctuation">:</span> todos <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useQuery</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'todos'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> fetchTodos<span class="token punctuation">)</span><span class="token punctuation">;</span> 
<span class="token keyword">const</span> <span class="token punctuation">{</span> data<span class="token punctuation">:</span> categories <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useQuery</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'categories'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> fetchCategories<span class="token punctuation">)</span><span class="token punctuation">;</span> 
<span class="token keyword">const</span> workCategory <span class="token operator">=</span> categories<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span>c <span class="token operator">=&gt;</span> c<span class="token punctuation">.</span>name <span class="token operator">===</span> <span class="token string">'Work'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
<span class="token keyword">const</span> uncompletedWorkTodos <span class="token operator">=</span> todos <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>t <span class="token operator">=&gt;</span> t<span class="token punctuation">.</span>categoryId <span class="token operator">===</span> workCategory<span class="token operator">?</span><span class="token punctuation">.</span>id<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>t <span class="token operator">=&gt;</span> <span class="token operator">!</span>t<span class="token punctuation">.</span>completed<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>This works. But notice what&rsquo;s happening? We&rsquo;re manually filtering and joining data, and code like this runs on every render. With 10 todos? It feels seamless. But scale that to a thousand todos, and we&rsquo;ll start feeling the lag, especially if we&rsquo;re not careful with memoization. Our app gets sluggish.</p><p>The issue here is that the todos cache and the categories cache don&rsquo;t know about each other. They&rsquo;re completely isolated. If we want to connect them, we&rsquo;d have to do that manually every single time.</p><h2 id="project-setup">Project Setup</h2><p>We&rsquo;re going to set up a simple to-do app from scratch. The goal is to build two lists, &ldquo;Pending&rdquo; and &ldquo;Completed,&rdquo; and watch items move between them instantly. No manual state management, no <code>useMemo</code> hooks for filtering, just a reactive, local-first database.</p><p>We&rsquo;ll use <a target="_blank" href="https://vite.dev/">Vite</a>. It&rsquo;s the fastest way to get a React + <a target="_blank" href="https://www.typescriptlang.org/">TypeScript</a> project running.</p><p>Open your terminal and run the following command:</p><pre class=" language-shell"><code class="prism  language-shell">npm create vite@latest tanstack-db-demo -- --template react-ts
</code></pre><p>Once that&rsquo;s finished, move into the new directory and install the default packages:</p><pre class=" language-shell"><code class="prism  language-shell">cd tanstack-db-demo
npm install
</code></pre><p>With the basics installed, let&rsquo;s add our two core libraries. We&rsquo;ll install <code>react-query</code> (the &ldquo;delivery service&rdquo;) and <code>react-db</code> (our new &ldquo;smart warehouse&rdquo;).</p><p>Next, we&rsquo;ll install TanStack Query to handle server syncing and TanStack DB to store that data in a queryable local database.</p><pre class=" language-shell"><code class="prism  language-shell">npm install @tanstack/react-query @tanstack/db
</code></pre><h3 id="setting-up-the-file-structure">Setting up the File Structure</h3><p>Let&rsquo;s clean up the <code>src</code> folder. You can delete the <code>App.css</code> file and the <code>assets</code> folder that Vite gives you. We&rsquo;ll replace them with our own <code>index.css</code> and two new files: <code>types.ts</code> and <code>db.ts</code>.</p><p>When you&rsquo;re done, your <code>src</code> folder should look like this:</p><pre class=" language-js"><code class="prism  language-js">src<span class="token operator">/</span>
── components<span class="token operator">/</span>   <span class="token punctuation">(</span>We'll add <span class="token keyword">this</span> later<span class="token punctuation">)</span>
── App<span class="token punctuation">.</span><span class="token function">tsx</span>       <span class="token punctuation">(</span>Already there<span class="token punctuation">,</span> we'll edit it<span class="token punctuation">)</span>
── db<span class="token punctuation">.</span><span class="token function">ts</span>         <span class="token punctuation">(</span>New <span class="token class-name">file</span><span class="token punctuation">)</span>
── index<span class="token punctuation">.</span><span class="token function">css</span>     <span class="token punctuation">(</span>Already there<span class="token punctuation">,</span> we'll edit it<span class="token punctuation">)</span>
── main<span class="token punctuation">.</span><span class="token function">tsx</span>      <span class="token punctuation">(</span>Already there<span class="token punctuation">,</span> we'll edit it<span class="token punctuation">)</span>
── types<span class="token punctuation">.</span><span class="token function">ts</span>      <span class="token punctuation">(</span>New <span class="token class-name">file</span><span class="token punctuation">)</span>
</code></pre><h2 id="defining-the-local-collection">Defining the Local Collection</h2><p>With our project set up, let&rsquo;s get to the core of our app&rsquo;s data logic. We&rsquo;ll do this in a new file, <code>src/db.ts</code>. It&rsquo;s important to understand that TanStack DB is built to work with TanStack Query, not replace it.</p><p>This <code>db.ts</code> file will set up both the <strong>QueryClient</strong>, which is the standard engine from TanStack Query, and the main cache that all our data will flow through, and the <strong>Collection</strong>, which is the new part from TanStack DB&mdash;our actual, reactive table that will hold the todos.</p><p>We&rsquo;ll start with <code>localOnlyCollectionOptions</code> to build a simple, in-memory collection first. This lets us build our UI without worrying about a server yet. Go ahead and add the following to your <code>src/db.ts</code> file:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> QueryClient <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@tanstack/react-query"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  createCollection<span class="token punctuation">,</span>
  localOnlyCollectionOptions<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@tanstack/react-db"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> Todo <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./types"</span><span class="token punctuation">;</span> 
<span class="token keyword">export</span> <span class="token keyword">const</span> queryClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">QueryClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> initialTodos<span class="token punctuation">:</span> Todo<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> <span class="token string">"Learn TanStack DB"</span><span class="token punctuation">,</span> completed<span class="token punctuation">:</span> <span class="token keyword">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> <span class="token string">"Write the blog post"</span><span class="token punctuation">,</span> completed<span class="token punctuation">:</span> <span class="token keyword">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> <span class="token string">'Show "live queries"'</span><span class="token punctuation">,</span> completed<span class="token punctuation">:</span> <span class="token keyword">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> todoCollection <span class="token operator">=</span> createCollection<span class="token operator">&lt;</span>Todo<span class="token punctuation">,</span> <span class="token keyword">number</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>
  <span class="token function">localOnlyCollectionOptions</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    id<span class="token punctuation">:</span> <span class="token string">"todos"</span><span class="token punctuation">,</span>
    getKey<span class="token punctuation">:</span> <span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> todo<span class="token punctuation">.</span>id<span class="token punctuation">,</span>
    initialData<span class="token punctuation">:</span> initialTodos<span class="token punctuation">,</span> <span class="token comment">// Load the dummy data on start</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The code snippet above is pretty straightforward. Let&rsquo;s break it down and be clear on what each part does:</p><ul><li><strong>queryClient</strong>: This is just the standard QueryClient from <code>@tanstack/react-query</code>. We create one and export it because our whole app needs to share a single cache.</li><li><strong>initialTodos</strong>: This is just some dummy data, so our app doesn&rsquo;t start empty.</li><li><strong>todoCollection</strong>: This is the core of our setup. We&rsquo;re defining our &ldquo;table.&rdquo;</li><li><strong>localOnlyCollectionOptions</strong>: This is our starting point. It&rsquo;s a helper that tells TanStack DB to be a local-only database. It won&rsquo;t try to fetch anything or talk to a server. It&rsquo;s the perfect way to build out our UI before we&rsquo;ve written an API.</li><li><strong>getKey</strong>: This is important. It&rsquo;s the primary key for our &ldquo;table,&rdquo; telling TanStack DB how to find any specific to-do. So we&rsquo;ll just use <code>todo.id</code>.</li></ul><p>Now, we have a fully typed, in-memory database populated with initial data, all in one file. We just need to tell our React app to actually use this setup. We&rsquo;ll do that in the next step by wiring up our queryClient in <code>main.tsx</code> file.</p><h2 id="configuring-the-app">Configuring the App</h2><p>We have our <code>queryClient</code> and <code>todoCollection</code> defined in the <code>src/db.ts</code> file . But the thing is, our React app doesn&rsquo;t automatically know they exist. They&rsquo;re just isolated pieces of code right now.</p><p>To make everything work together, we need to connect that <code>queryClient</code> to our component tree. This isn&rsquo;t a TanStack DB-specific thing; it&rsquo;s how TanStack Query works, and we&rsquo;ll need a <code>QueryClientProvider</code> at the root. This provider uses React Context under the hood to pass the client instance down, making sure all your hooks (useQuery, useMutation and eventually useLiveQuery) are all talking to the same central cache.</p><p>It&rsquo;s a straightforward setup in our main entry file, <code>src/main.tsx</code>. We just need to do two things:</p><ul><li>Import the <code>queryClient</code> that we already exported from <code>./db</code></li><li>Wrap our main <code>&lt;App /&gt;</code> component with <code>&lt;QueryClientProvider&gt;</code>, passing that imported <code>queryClient</code> to its client prop</li></ul><p>Here&rsquo;s what that looks like in the code:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> StrictMode <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> createRoot <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom/client"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> QueryClientProvider <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@tanstack/react-query"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token string">"./index.css"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> App <span class="token keyword">from</span> <span class="token string">"./App.tsx"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> queryClient <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./db"</span><span class="token punctuation">;</span>
<span class="token function">createRoot</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"root"</span><span class="token punctuation">)</span><span class="token operator">!</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span>
  <span class="token operator">&lt;</span>StrictMode<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>QueryClientProvider client<span class="token operator">=</span><span class="token punctuation">{</span>queryClient<span class="token punctuation">}</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>App <span class="token operator">/</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>QueryClientProvider<span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span><span class="token operator">/</span>StrictMode<span class="token operator">&gt;</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>With that provider set up, our app is ready. The <code>queryClient</code> is available everywhere, which means TanStack DB can now hook into it. All the groundwork is done.</p><p>Next, let&rsquo;s build the UI in <code>App.tsx</code> file and see how <code>useLiveQuery</code> pulls our data into the components.</p><h2 id="building-the-ui-with-live-queries">Building the UI with Live Queries</h2><p>We have our setup at this point. Our <code>queryClient</code> is provided, and our <code>todoCollection</code> is ready, so the next thing is to pull our data into the UI.</p><p>This is where <code>useLiveQuery</code> comes in. It&rsquo;s a hook TanStack DB gives us to read from our database, and it&rsquo;s the core of what makes this whole setup &ldquo;reactive.&rdquo; In this context, &ldquo;reactive&rdquo; means our UI will update immediately and automatically whenever our data changes, without us having to force a re-render manually.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/ui-update-immediately.png?sfvrsn=1ddd99e6_2" title="UI update immediately data changes, without  forcing a re-render manually" alt="UI update immediately data changes, without  forcing a re-render manually" /></p><p>If we were doing this the old way, we would fetch data, dump it into our <code>useState</code> hook, and then if we added a new todo, we would have to call <code>setTodos([...todos, newTodo])</code> just to see the change.</p><p>But with <code>useLiveQuery</code>, we don&rsquo;t need to do that. Our component subscribes to the database, and when we call <code>todoCollection.insert()</code>, the <code>useLiveQuery</code> sees the change, retrieves the new data, and our component re-renders.</p><p>Let&rsquo;s look at <code>useLiveQuery</code> as subscribing to your database. What happens behind the scenes is this: when your component mounts, useLiveQuery subscribes to the database. It runs your query and gives you the current data, then keeps watching the database for any changes. When data changes (insert, update, delete), it automatically reruns your query. Your component receives the fresh data and re-renders, without you having to manage any state manually.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/components-update-automatically.png?sfvrsn=37043fd8_2" title="When database changes both components update automatically" alt="When database changes both components update automatically" /></p><p>Let&rsquo;s build our UI. We&rsquo;ll start by creating two simple components: <code>TodoForm</code> and <code>TodoList</code>.</p><h2 id="creating-components">Creating Components</h2><p>Run the command below in your terminal to create a new <code>src/components</code> folder:</p><pre class=" language-shell"><code class="prism  language-shell">mkdir src/components
</code></pre><p>We&rsquo;ll put our new components here. These are presentational components&mdash;they just take props and render UI. They have no knowledge of TanStack DB.</p><p>Create a <code>src/components/TodoForm.tsx</code> file and add the following to it:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
type TodoFormProps <span class="token operator">=</span> <span class="token punctuation">{</span>
  onAdd<span class="token punctuation">:</span> <span class="token punctuation">(</span>text<span class="token punctuation">:</span> string<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">void</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">TodoForm</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> onAdd <span class="token punctuation">}</span><span class="token punctuation">:</span> TodoFormProps<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>newTodoText<span class="token punctuation">,</span> setNewTodoText<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token function-variable function">handleSubmit</span> <span class="token operator">=</span> <span class="token punctuation">(</span>e<span class="token punctuation">:</span> React<span class="token punctuation">.</span>FormEvent<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>newTodoText<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token function">onAdd</span><span class="token punctuation">(</span>newTodoText<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">setNewTodoText</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">onSubmit</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span></span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>todo-form<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
        <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span>
        <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>newTodoText<span class="token punctuation">}</span></span>
        <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setNewTodoText</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
        <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>What needs to be done?<span class="token punctuation">"</span></span>
        <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>todo-input<span class="token punctuation">"</span></span>
      <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>todo-add-button<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        Add
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre><p>This is a controlled component that manages the input field&rsquo;s value in its own state. When submitted, it passes the text up to the parent component via the <code>onAdd</code> prop.</p><p>Create a <code>src/components/TodoList.tsx</code> file and add the following to it:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> type <span class="token punctuation">{</span> Todo <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"../types"</span><span class="token punctuation">;</span>
type TodoListProps <span class="token operator">=</span> <span class="token punctuation">{</span>
title<span class="token punctuation">:</span> string<span class="token punctuation">;</span>
todos<span class="token punctuation">:</span> Todo<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
onToggle<span class="token punctuation">:</span> <span class="token punctuation">(</span>todo<span class="token punctuation">:</span> Todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">void</span><span class="token punctuation">;</span>
onDelete<span class="token punctuation">:</span> <span class="token punctuation">(</span>todo<span class="token punctuation">:</span> Todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">void</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">TodoList</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
title<span class="token punctuation">,</span>
todos<span class="token punctuation">,</span>
onToggle<span class="token punctuation">,</span>
onDelete<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">:</span> TodoListProps<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>todo-list-container<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>todo-list-title<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">{</span>title<span class="token punctuation">}</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>todos<span class="token punctuation">.</span>length<span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
    <span class="token punctuation">{</span>todos<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">0</span> <span class="token operator">?</span> <span class="token punctuation">(</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>todo-item-placeholder<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Nothing here<span class="token operator">!</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>todo-list<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token punctuation">{</span>todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> checkboxId <span class="token operator">=</span> <span class="token template-string"><span class="token string">`todo-checkbox-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>todo<span class="token punctuation">.</span>id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">;</span>
          <span class="token keyword">return</span> <span class="token punctuation">(</span>
            <span class="token operator">&lt;</span>li
              key<span class="token operator">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span>
              className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token string">`todo-item </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>todo<span class="token punctuation">.</span>completed <span class="token operator">?</span> <span class="token string">"completed"</span> <span class="token punctuation">:</span> <span class="token string">""</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">}</span>
            <span class="token operator">&gt;</span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
                <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>checkbox<span class="token punctuation">"</span></span>
                <span class="token attr-name">id</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>checkboxId<span class="token punctuation">}</span></span>
                <span class="token attr-name">checked</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>completed<span class="token punctuation">}</span></span>
                <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">onToggle</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>todo-item-checkbox<span class="token punctuation">"</span></span>
              <span class="token punctuation">/&gt;</span></span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span>
                <span class="token attr-name">htmlFor</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>checkboxId<span class="token punctuation">}</span></span>
                <span class="token attr-name">style</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> color<span class="token punctuation">:</span> <span class="token string">"black"</span><span class="token punctuation">,</span> display<span class="token punctuation">:</span> <span class="token string">"inline"</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span>
              <span class="token punctuation">&gt;</span></span>
                <span class="token punctuation">{</span>todo<span class="token punctuation">.</span>text <span class="token operator">||</span> <span class="token string">"NO TEXT"</span><span class="token punctuation">}</span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
                <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">onDelete</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>todo-delete-button<span class="token punctuation">"</span></span>
              <span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span>
                  <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<span class="token punctuation">"</span></span>
                  <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>none<span class="token punctuation">"</span></span>
                  <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>0 0 24 24<span class="token punctuation">"</span></span>
                  <span class="token attr-name">stroke</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>currentColor<span class="token punctuation">"</span></span>
                <span class="token punctuation">&gt;</span></span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>path</span>
                    <span class="token attr-name">strokeLinecap</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>round<span class="token punctuation">"</span></span>
                    <span class="token attr-name">strokeLinejoin</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>round<span class="token punctuation">"</span></span>
                    <span class="token attr-name">strokeWidth</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token number">2</span><span class="token punctuation">}</span></span>
                    <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16<span class="token punctuation">"</span></span>
                  <span class="token punctuation">/&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>svg</span><span class="token punctuation">&gt;</span></span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
          <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">&gt;</span></span>
    <span class="token punctuation">)</span><span class="token punctuation">}</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre><p>This component is only responsible for displaying the list of todos. It receives the todos array as a prop, shows a &ldquo;Nothing here!&rdquo; message if the list is empty, or maps over the array to render each item.</p><h2 id="updating-app.tsx-file">Updating App.tsx File</h2><p>Now let&rsquo;s open <code>src/App.tsx</code> and wire everything together. First, we need to import our new components <code>(TodoForm and TodoList)</code>. Then we&rsquo;ll call <code>useLiveQuery</code> twice&mdash;one query to get all todos where <code>completed</code> is false, and a second query to get all todos where <code>completed</code> is true.</p><p>Next, we&rsquo;ll create our event handlers (<code>handleAddTodo</code>, <code>handleToggleTodo</code>, <code>handleDeleteTodo</code>), which is where we write to the database. Finally, we&rsquo;ll render the components and pass the data and handlers as props.</p><p>Here&rsquo;s what our <code>src/App.tsx</code> file should look like:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> <span class="token punctuation">{</span> useMemo <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useLiveQuery<span class="token punctuation">,</span> eq <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@tanstack/react-db"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> todoCollection <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./db"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> type <span class="token punctuation">{</span> Todo <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./types"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> TodoForm <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./components/TodoForm"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> TodoList <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./components/TodoList"</span><span class="token punctuation">;</span>
<span class="token keyword">function</span> <span class="token function">TodoApp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> data<span class="token punctuation">:</span> pendingTodos <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useLiveQuery</span><span class="token punctuation">(</span><span class="token punctuation">(</span>q<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
    q
      <span class="token punctuation">.</span><span class="token keyword">from</span><span class="token punctuation">(</span><span class="token punctuation">{</span> todo<span class="token punctuation">:</span> todoCollection <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">where</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">{</span> todo <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">eq</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>completed<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> data<span class="token punctuation">:</span> completedTodos <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useLiveQuery</span><span class="token punctuation">(</span><span class="token punctuation">(</span>q<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
    q
      <span class="token punctuation">.</span><span class="token keyword">from</span><span class="token punctuation">(</span><span class="token punctuation">{</span> todo<span class="token punctuation">:</span> todoCollection <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">where</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">{</span> todo <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">eq</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>completed<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> sortedPending <span class="token operator">=</span> <span class="token function">useMemo</span><span class="token punctuation">(</span>
    <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token operator">...</span>pendingTodos<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">reverse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">[</span>pendingTodos<span class="token punctuation">]</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> sortedCompleted <span class="token operator">=</span> <span class="token function">useMemo</span><span class="token punctuation">(</span>
    <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token operator">...</span>completedTodos<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">reverse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">[</span>completedTodos<span class="token punctuation">]</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token function-variable function">handleAddTodo</span> <span class="token operator">=</span> <span class="token punctuation">(</span>text<span class="token punctuation">:</span> string<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> newTodo<span class="token punctuation">:</span> Todo <span class="token operator">=</span> <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      text<span class="token punctuation">,</span>
      completed<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"APP: Inserting new todo"</span><span class="token punctuation">,</span> newTodo<span class="token punctuation">)</span><span class="token punctuation">;</span>
    todoCollection<span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span>newTodo<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token function-variable function">handleToggleTodo</span> <span class="token operator">=</span> <span class="token punctuation">(</span>todo<span class="token punctuation">:</span> Todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"APP: Toggling todo"</span><span class="token punctuation">,</span> todo<span class="token punctuation">)</span><span class="token punctuation">;</span>
    todoCollection<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">,</span> <span class="token punctuation">(</span>draft<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      draft<span class="token punctuation">.</span>completed <span class="token operator">=</span> <span class="token operator">!</span>draft<span class="token punctuation">.</span>completed<span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token function-variable function">handleDeleteTodo</span> <span class="token operator">=</span> <span class="token punctuation">(</span>todo<span class="token punctuation">:</span> Todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"APP: Deleting todo"</span><span class="token punctuation">,</span> todo<span class="token punctuation">)</span><span class="token punctuation">;</span>
    todoCollection<span class="token punctuation">.</span><span class="token keyword">delete</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>app-container<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>app-title<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>TanStack DB To<span class="token operator">-</span>Do<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TodoForm</span> <span class="token attr-name">onAdd</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleAddTodo<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TodoList</span>
        <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Pending<span class="token punctuation">"</span></span>
        <span class="token attr-name">todos</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>sortedPending<span class="token punctuation">}</span></span>
        <span class="token attr-name">onToggle</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleToggleTodo<span class="token punctuation">}</span></span>
        <span class="token attr-name">onDelete</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleDeleteTodo<span class="token punctuation">}</span></span>
      <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TodoList</span>
        <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Completed<span class="token punctuation">"</span></span>
        <span class="token attr-name">todos</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>sortedCompleted<span class="token punctuation">}</span></span>
        <span class="token attr-name">onToggle</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleToggleTodo<span class="token punctuation">}</span></span>
        <span class="token attr-name">onDelete</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleDeleteTodo<span class="token punctuation">}</span></span>
      <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> TodoApp<span class="token punctuation">;</span>
</code></pre><p>Notice the <code>useLiveQuery</code> hooks and what they look like when you&rsquo;re querying a SQL database. If you run <code>npm run dev</code> at this point, you&rsquo;ll have a local-only to-do app.</p><p>The key takeaway here is our <code>App</code> component doesn&rsquo;t manage any state. There are no <code>useState</code> hooks for the to-do lists. It just asks TanStack DB for two different lists (<code>Pending</code> and <code>Completed</code>).</p><p>When you add a new to-do, <code>handleAddTodo</code> calls <code>todoCollection.insert()</code>. The data is added to the local database, and TanStack DB automatically reruns any query affected by this change. The UI updates instantly because we&rsquo;re just writing to a local database. This is a concept called an &ldquo;optimistic update,&rdquo; and we get it for free.</p><p>Right now, this is all happening in the browser. In the next step, we&rsquo;ll connect this to a server.</p><h2 id="syncing-to-a-server">Syncing to a Server</h2><p>Before we update our <code>db.ts</code> file, we need an API to talk to. We don&rsquo;t have a real backend, so we&rsquo;re going to simulate a fake one. This is the best way to see optimistic updates in action because we can add an artificial delay to simulate real network lag.</p><p>Let&rsquo;s create a new file, <code>src/api.ts</code>, that uses localStorage to save todos so they actually persist when we refresh. And we&rsquo;ll add a one-second setTimeout to every request to mimic what it feels like when your app is talking to a real server.</p><p>Add the following to your <code>src/api.ts</code> file:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> Todo <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./types"</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> TODOS_STORAGE_KEY <span class="token operator">=</span> <span class="token string">"todos"</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token function-variable function">wait</span> <span class="token operator">=</span> <span class="token punctuation">(</span>ms<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span>resolve<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> ms<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> loadTodos <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> Todo<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> data <span class="token operator">=</span> localStorage<span class="token punctuation">.</span><span class="token function">getItem</span><span class="token punctuation">(</span>TODOS_STORAGE_KEY<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> data <span class="token operator">?</span> <span class="token punctuation">(</span>JSON<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span> <span class="token keyword">as</span> Todo<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token function-variable function">saveTodos</span> <span class="token operator">=</span> <span class="token punctuation">(</span>todos<span class="token punctuation">:</span> Todo<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  localStorage<span class="token punctuation">.</span><span class="token function">setItem</span><span class="token punctuation">(</span>TODOS_STORAGE_KEY<span class="token punctuation">,</span> JSON<span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>todos<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> api <span class="token operator">=</span> <span class="token punctuation">{</span>
  todos<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    getAll<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">await</span> <span class="token function">wait</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Simulate network delay</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"SERVER: (GET) Fetched all todos"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token function">loadTodos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    create<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span>newTodo<span class="token punctuation">:</span> Todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">await</span> <span class="token function">wait</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> todos <span class="token operator">=</span> <span class="token function">loadTodos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> updatedTodos <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span>todos<span class="token punctuation">,</span> newTodo<span class="token punctuation">]</span><span class="token punctuation">;</span>
      <span class="token function">saveTodos</span><span class="token punctuation">(</span>updatedTodos<span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"SERVER: (POST) created new todo"</span><span class="token punctuation">,</span> newTodo<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> newTodo<span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    update<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span>updatedTodo<span class="token punctuation">:</span> Todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">await</span> <span class="token function">wait</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> todos <span class="token operator">=</span> <span class="token function">loadTodos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> updatedTodos <span class="token operator">=</span> todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
        todo<span class="token punctuation">.</span>id <span class="token operator">===</span> updatedTodo<span class="token punctuation">.</span>id <span class="token operator">?</span> updatedTodo <span class="token punctuation">:</span> todo
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">saveTodos</span><span class="token punctuation">(</span>updatedTodos<span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"SERVER: (PUT) updated todo"</span><span class="token punctuation">,</span> updatedTodo<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> updatedTodo<span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token keyword">delete</span><span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span>id<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">await</span> <span class="token function">wait</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> todos <span class="token operator">=</span> <span class="token function">loadTodos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> updatedTodos <span class="token operator">=</span> todos<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> todo<span class="token punctuation">.</span>id <span class="token operator">!==</span> id<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">saveTodos</span><span class="token punctuation">(</span>updatedTodos<span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"SERVER: (DELETE) deleted todo"</span><span class="token punctuation">,</span> id<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span> id <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre><p>Now that we have our <code>src/api.ts</code> ready, the next step is to update our <code>db.ts</code> to tell it to use our API. This is where we&rsquo;ll swap the <code>localOnlyCollectionOptions</code> for <code>queryCollectionOptions</code>, just as we discussed earlier.</p><p>At this point, we need to do three things: install the adapter package that connects TanStack Query and TanStack DB, import the <code>queryCollectionOptions</code> from this new package, and replace <code>localOnlyCollectionOptions</code> with <code>queryCollectionOptions</code>.</p><p>Run this install command in your terminal:</p><pre class=" language-shell"><code class="prism  language-shell">npm install @tanstack/query-db-collection
</code></pre><blockquote><p>This package gives us the bridge between TanStack Query (server state) and TanStack DB (local state).</p></blockquote><p>Now replace the entire content of your <code>src/db.ts</code> file with the following:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> QueryClient <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@tanstack/react-query"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> createCollection <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@tanstack/react-db"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> queryCollectionOptions <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@tanstack/query-db-collection"</span><span class="token punctuation">;</span> <span class="token comment">//new import</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> api <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./api"</span><span class="token punctuation">;</span> <span class="token comment">// import simulated API</span>
<span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> Todo <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./types"</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> queryClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">QueryClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//we no longer need the initialTodos. The API will provide that to us</span>
<span class="token comment">// const initialTodos: Todo[] = [</span>
<span class="token comment">//   { id: 1, text: "Learn TanStack DB", completed: true },</span>
<span class="token comment">//   { id: 2, text: "Write the blog post", completed: false },</span>
<span class="token comment">//   { id: 3, text: 'Show "live queries"', completed: false },</span>
<span class="token comment">// ];</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> todoCollection <span class="token operator">=</span> createCollection<span class="token operator">&lt;</span>Todo<span class="token punctuation">,</span> <span class="token keyword">number</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>
  <span class="token function">queryCollectionOptions</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    queryClient<span class="token punctuation">,</span>
    queryKey<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"todos"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    queryFn<span class="token punctuation">:</span> api<span class="token punctuation">.</span>todos<span class="token punctuation">.</span>getAll<span class="token punctuation">,</span>
    getKey<span class="token punctuation">:</span> <span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> todo<span class="token punctuation">.</span>id<span class="token punctuation">,</span>
    onInsert<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> transaction <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"DB: Inserting..."</span><span class="token punctuation">,</span> transaction<span class="token punctuation">.</span>mutations<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>modified<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">await</span> api<span class="token punctuation">.</span>todos<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>transaction<span class="token punctuation">.</span>mutations<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>modified <span class="token keyword">as</span> Todo<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    onUpdate<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> transaction <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"DB: Updating..."</span><span class="token punctuation">,</span> transaction<span class="token punctuation">.</span>mutations<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>modified<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">await</span> api<span class="token punctuation">.</span>todos<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span>transaction<span class="token punctuation">.</span>mutations<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>modified <span class="token keyword">as</span> Todo<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    onDelete<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> transaction <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"DB: Deleting..."</span><span class="token punctuation">,</span> transaction<span class="token punctuation">.</span>mutations<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>original<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">await</span> api<span class="token punctuation">.</span>todos<span class="token punctuation">.</span><span class="token keyword">delete</span><span class="token punctuation">(</span>transaction<span class="token punctuation">.</span>mutations<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>original<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Start your app and try adding a new todo or toggling an existing one. The UI updates instantly, right? Now open your browser console and watch the sequence:</p><ul><li><strong>Immediately</strong>: <code>DB: Inserting&hellip;</code> &ndash; our local database write</li><li><strong>One second later</strong>: <code>SERVER: Created new todo...</code> &ndash; server sync</li></ul><p>This is the optimistic update in action, and it&rsquo;s an important concept. The simple idea is we update the UI immediately, before we&rsquo;ve even confirmed the change with the server. Our app is being optimistic that the server request will succeed.</p><p>The user gets an app that feels fast and instant. All the work of saving data happens in the background. The user never sees a loading spinner. They never wait. They just see their change appear immediately.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/optimistic-data-flow.png?sfvrsn=bc957275_2" title="Optimistic data flow" alt="Optimistic data flow" /></p><p>Let&rsquo;s break the above diagram down. It starts with the user clicking a button in the app. The UI sends a write command to the database: <code>todoCollection.insert()</code>. That&rsquo;s all, just write to the local database.</p><p>Now here is where the fun happens. The moment that the local database receives the new data, it does two things at the same time:</p><ul><li>Immediate optimistic update &ndash; The <code>useLiveQuery()</code> hook in our app is always listening. It gets the new data instantly. The app re-renders, and the user sees their new todo appear.</li><li>Background server sync &ndash; At the same time, the local database triggers the server sync. It calls the <code>onInsert</code> function we wrote, which starts the slow one-second request to the server.</li></ul><p>The key takeaway here is that the user&rsquo;s experience is only tied to Step 1, that is, the immediate update. They get instant feedback. All the slow/heavy requests happen in the background.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/no-delay.gif?sfvrsn=577752fc_2" title="The UI doesn’t wait for the 1 second delay" alt="The UI doesn’t wait for the 1 second delay" /></p><h2 id="differential-data-flow">Differential Data-Flow</h2><p>We&rsquo;ve talked about live queries and optimistic updates. Now let&rsquo;s look at what makes TanStack DB fast: differential dataflow. Let&rsquo;s break down this concept to understand why TanStack DB feels so smooth.</p><p>In a React app, when data changes, you recalculate everything that depends on it. For instance, say we have 2,000 todos and you mark one as completed. What happens?</p><p>One approach is:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">const</span> pendingTodos <span class="token operator">=</span> todos<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>t <span class="token operator">=&gt;</span> <span class="token operator">!</span>t<span class="token punctuation">.</span>completed<span class="token punctuation">)</span><span class="token punctuation">;</span> 
<span class="token keyword">const</span> completedTodos <span class="token operator">=</span> todos<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>t <span class="token operator">=&gt;</span> t<span class="token punctuation">.</span>completed<span class="token punctuation">)</span><span class="token punctuation">;</span> 
<span class="token keyword">const</span> pendingCount <span class="token operator">=</span> pendingTodos<span class="token punctuation">.</span>length<span class="token punctuation">;</span> 
<span class="token keyword">const</span> completedCount <span class="token operator">=</span> completedTodos<span class="token punctuation">.</span>length<span class="token punctuation">;</span>
</code></pre><p>This is the traditional approach. One thing changes, and you had to loop through 2,000 todos twice, then count them both. With a small number of todos&mdash;let&rsquo;s say 10-20&mdash;this won&rsquo;t be a problem, but with over a thousand, the app might start to feel slow.</p><p>Let&rsquo;s look at what happens under the hood when we have 2,000 todos:</p><ul><li>Loop through 2,000 todos and filter pending todos&mdash;that&rsquo;s 2,000 operations</li><li>Loop through 2,000 todos again to filter completed todos&mdash;another 2,000 operations</li><li>Count pending&mdash;one operation</li><li>Count completed&mdash;one operation</li></ul><p>At the end of the day, we&rsquo;ll have over 4,000 operations just for this simple computation of finding completed tasks.</p><p>On the other hand, with differential dataflow, it just asks: &ldquo;What changed?&rdquo; Instead of recalculating everything, it only updates what was affected.</p><p>Let&rsquo;s look at how differential dataflow handles it:</p><ul><li>First, it detects that todo #101 has changed</li><li>Next, it figures out which queries care:
        <ul><li>Pending list (remove todo #101)</li><li>Completed list (add todo #101)</li><li>Pending count (subtract 1)</li><li>Completed count (add 1)</li></ul></li></ul><p>That&rsquo;s approximately five operations.</p><p>Notice the difference: the first approach loops through everything. Differential dataflow only cares about what changed. One todo changed, so it does the work for one todo. The rest of the data remains untouched.</p><h2 id="when-to-use-tanstack-db">When to Use TanStack DB</h2><p>TanStack DB makes the most sense when you&rsquo;re dealing with related data. If you have todos connected to categories, posts linked to authors or products with reviews, it makes working with those relationships way easier than manually joining arrays.</p><p>TanStack DB is also a great fit if you need to run complex queries on the client side or if you&rsquo;re building an app that needs real-time UI updates. If you&rsquo;re building an offline-first app where users need to work without an internet connection and sync when they&rsquo;re back online, TanStack DB is built to handle that.</p><p>On the other hand, if your data is simple, maybe you&rsquo;re just fetching a list or a single blog post, TanStack Query alone is fine. There are no relationships to handle, so TanStack DB isn&rsquo;t worth it.</p><p>And if your data rarely changes and you&rsquo;re OK with manual refetching, live queries are probably overkill. TanStack DB isn&rsquo;t for every app, but when you need it, it does a very good job.</p><h2 id="conclusion">Conclusion</h2><p>So that&rsquo;s TanStack DB. A reactive database that lives in your browser gives you relationships between your data, updates your UI instantly with live queries, and stays fast even with thousands of items&mdash;all thanks to differential dataflow.</p><p>It&rsquo;s important to note that it&rsquo;s not replacing TanStack Query. It works alongside it. TanStack Query handles your server state: fetching from APIs, caching and keeping things in sync. TanStack DB handles your client state: storing that data locally and letting you query it like a real database. Together, they give you the best of both worlds&mdash;server syncing and fast local queries.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Caching with TanStack Query</h4></div><div class="col-8"><p class="u-fs16 u-mb0"><a target="_blank" href="https://www.telerik.com/blogs/caching-tanstack-query">TanStack Query caching</a> creates an instantaneous feeling user experience. Combined with the KendoReact Loader component, we have a polished React app handling even complex server state smoothly.</p></div></div></aside><img src="https://feeds.telerik.com/link/23056/17288834.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:ca3a3fbd-f3ef-420c-8945-38ae0e265bde</id>
    <title type="text">React Basics: Memoization in React</title>
    <summary type="text">Don’t let re-rendering hamstring your React app: memoize! Learn when and how to memorize to improve the performance of your React app.</summary>
    <published>2026-02-02T17:34:37Z</published>
    <updated>2026-04-23T22:50:00Z</updated>
    <author>
      <name>David Adeneye Abiodun </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23056/17268597/react-basics-memoization-react"/>
    <content type="text"><![CDATA[<p><span class="featured">Don&rsquo;t let re-rendering hamstring your React app: memoize! Learn when and how to memorize to improve the performance of your React app.</span></p><p>If you&rsquo;ve ever worked on a React app that started out snappy and slowly turned sluggish as it grew, you&rsquo;ve probably run into one of React&rsquo;s classic performance puzzles&mdash;re-renders.</p><p>You click a button, update a state and suddenly half your component tree decides to re-render itself. Now, the UI works fine, but something feels off. Things start to lag. And before long, you&rsquo;re Googling &ldquo;why is my React component re-rendering&rdquo; for the 10th time that week.</p><p>That&rsquo;s where memoization steps in. It&rsquo;s one of those optimization tools that, once you understand it, gives you control over when your components and calculations actually update, instead of letting React do it blindly.</p><p>But if you&rsquo;ve ever tried to optimize performance in a large React app, you know how easy it is to overdo it. Suddenly, your code is buried under layers of memo hooks, dependency arrays and &ldquo;why isn&rsquo;t this memoized&rdquo; comments. Performance tuning starts to feel like superstition; sometimes it helps, sometimes it hurts, and often it just adds noise.</p><p>In this deep dive, we will unpack how memoization really works in React and how the landscape is changing with React 19&rsquo;s compiler, which is rewriting the rules entirely. By the end, you&rsquo;ll not only understand memoization, but you&rsquo;ll also know when to stop worrying about it and finally how React 19 is making manual memoization almost obsolete.</p><h2 id="why-memoization-matters">Why Memoization Matters</h2><p>React&rsquo;s rendering model is simple but aggressive. Whenever a parent component re-renders, its children will usually re-render too, even if their props haven&rsquo;t changed. Most of the time, this is fine. But when your components grow complex or involve expensive computations (such as filtering, sorting or formatting data), unnecessary renders start to accumulate.</p><p>Let&rsquo;s say you have a large list of users, and every time you type in a search box, the entire list recalculates and re-renders. Even if only one prop changed, React doesn&rsquo;t know whether the results are the same, so it plays it safe and re-renders everything.</p><p>Memoization helps fix that by letting React remember what didn&rsquo;t change.</p><h2 id="what-is-memoization-exactly">What Is Memoization, Exactly?</h2><p>Memoization is just a fancy term for caching the result of a function so you don&rsquo;t recompute it unnecessarily.</p><p>Here&rsquo;s a plain JavaScript example to show what it means:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">function</span> <span class="token function">slowSquare</span><span class="token punctuation">(</span>n<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Computing...'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> n <span class="token operator">*</span> n<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">slowSquare</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "Computing..." &rarr; 16</span>
<span class="token function">slowSquare</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "Computing..." &rarr; 16 again</span>
</code></pre><p>Every call recalculates. Now let&rsquo;s memoize it:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> cache <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">function</span> <span class="token function">memoizedSquare</span><span class="token punctuation">(</span>n<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>cache<span class="token punctuation">[</span>n<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">return</span> cache<span class="token punctuation">[</span>n<span class="token punctuation">]</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Computing...'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  cache<span class="token punctuation">[</span>n<span class="token punctuation">]</span> <span class="token operator">=</span> n <span class="token operator">*</span> n<span class="token punctuation">;</span>
  <span class="token keyword">return</span> cache<span class="token punctuation">[</span>n<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">memoizedSquare</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "Computing..." &rarr; 16</span>
<span class="token function">memoizedSquare</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// (no log) &rarr; 16 from cache</span>
</code></pre><p>The second time, it skips the heavy work because the inputs haven&rsquo;t changed.</p><p>That&rsquo;s all memoization is. It&rsquo;s a performance optimization that remembers past results based on inputs.</p><p>React applies this same concept to rendering and state updates. React&rsquo;s job is to re-render your UI when state or props change. But sometimes, it&rsquo;s re-rendering too much. So React gives us three tools to take control of this:</p><ul><li><code>React.memo</code> &ndash; memoizes components</li><li><code>useMemo</code> &ndash; memoizes values</li><li><code>useCallback</code> &ndash; memoizes functions</li></ul><p>Each one targets a different kind of unnecessary work. Let&rsquo;s go through them one by one.</p><h2 id="react.memo-memoizing-components">React.memo: Memoizing Components</h2><p>When a parent component re-renders, all its children re-render by default, even if their props are identical. <code>React.memo</code> changes that.</p><p>It wraps a functional component and tells React:</p><blockquote><p>&ldquo;If the props are the same as last time, skip re-rendering.&rdquo;</p></blockquote><p>Here&rsquo;s an example:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> TodoCard <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">memo</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">TodoCard</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Rendering:'</span><span class="token punctuation">,</span> name<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span><span class="token punctuation">{</span>name<span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>If you render multiple <code>TodoCard</code> components inside a parent that re-renders often, you&rsquo;ll notice only the ones with changed props actually re-render.</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">function</span> <span class="token function">TodoList</span><span class="token punctuation">(</span><span class="token punctuation">{</span> todos <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span>
      <span class="token punctuation">{</span>todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>todo <span class="token operator">=&gt;</span> <span class="token punctuation">(</span>
        <span class="token operator">&lt;</span>TodoCard key<span class="token operator">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span> name<span class="token operator">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>name<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
      <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>If the todos array reference stays the same, <code>React.memo</code> will prevent redundant renders.</p><h3 id="shallow-comparison-caveat">Shallow Comparison Caveat</h3><p><code>React.memo</code> uses a shallow comparison for props. That means if you pass a new object or array each time (even with the same contents), React will still think it changed:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TodoCard</span> <span class="token attr-name">todo</span><span class="token attr-value"><span class="token punctuation">=</span>{{</span> <span class="token attr-name"><span class="token namespace">name:</span></span> <span class="token attr-name">&ldquo;Write</span> <span class="token attr-name">React</span> <span class="token attr-name">Article&rdquo;</span> <span class="token attr-name">}}</span> <span class="token punctuation">/&gt;</span></span> // new object every render
</code></pre><p>In that case, memoization won&rsquo;t help unless you also memoize the object reference with <code>useMemo</code> or stabilize it in another way.</p><h2 id="usememo-memoizing-expensive-calculations">useMemo: Memoizing Expensive Calculations</h2><p>Sometimes, the performance hit doesn&rsquo;t come from re-renders&mdash;it comes from recalculations inside the render function. That&rsquo;s what <code>useMemo</code> is for.</p><p><code>useMemo</code> lets you <strong>cache a computed value</strong> between renders, only recomputing when its dependencies change.</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> cachedValue <span class="token operator">=</span> <span class="token function">useMemo</span><span class="token punctuation">(</span>calculateValue<span class="token punctuation">,</span> dependencies<span class="token punctuation">)</span>
</code></pre><p>To cache a calculation between re-renders, wrap it in a <code>useMemo</code> call at the top level of your component:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useMemo <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>
<span class="token keyword">function</span> <span class="token function">TodoApp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
&hellip;
<span class="token keyword">const</span> filteredTodos <span class="token operator">=</span> <span class="token function">useMemo</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Filtering todos..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> todos<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>todo <span class="token operator">=&gt;</span>
      todo<span class="token punctuation">.</span>text<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span>search<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>todos<span class="token punctuation">,</span> search<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token operator">...</span>
<span class="token punctuation">}</span>

</code></pre><p>When using <code>useMemo</code>, you need to pass two things:</p><ol><li>A <code>calculation function</code> takes no arguments, like <code>() =&gt;</code>, and returns what you wanted to calculate.</li><li>A <code>list of dependencies</code> including every value within your component that&rsquo;s used inside your calculation.</li></ol><p>On the initial render, React runs that calculation and stores the result.</p><p>On every subsequent render, React compares the current dependencies to the ones from the previous render (using <code>Object.is</code> for comparison).</p><ul><li>If none of the dependencies have changed, React simply returns the previously cached value&mdash;it doesn&rsquo;t rerun the calculation.</li><li>If at least one dependency has changed, React re-executes the function, updates the stored result and returns the new value.</li></ul><p>In short, <code>useMemo</code> remembers the result of a computation between renders and only recalculates it when one of its dependencies changes. It&rsquo;s React&rsquo;s way of saying, &ldquo;I&rsquo;ve already done this work. Unless something important changed, let&rsquo;s not do it again.&rdquo;</p><h3>Example: Optimizing a Filtered Todo List with useMemo</h3><p>Let&rsquo;s look at a simple example where <code>useMemo</code> actually makes a difference&mdash;a Todo list with a search filter.</p><p>Without <code>useMemo</code>, every time the component re-renders (even when unrelated state changes), your filter logic will run again. That&rsquo;s fine for small data, but as your list grows, it can start to slow things down unnecessarily.</p><p>Here&rsquo;s the straightforward version first:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">function</span> <span class="token function">TodoApp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>search<span class="token punctuation">,</span> setSearch<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>todos<span class="token punctuation">,</span> setTodos<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"Todo 1"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"Todo 2"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"Todo 3"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> filteredTodos <span class="token operator">=</span> todos<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>todo <span class="token operator">=&gt;</span>
    todo<span class="token punctuation">.</span>text<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span>search<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>input
        type<span class="token operator">=</span><span class="token string">"text"</span>
        placeholder<span class="token operator">=</span><span class="token string">"Search todos..."</span>
        value<span class="token operator">=</span><span class="token punctuation">{</span>search<span class="token punctuation">}</span>
        onChange<span class="token operator">=</span><span class="token punctuation">{</span>e <span class="token operator">=&gt;</span> <span class="token function">setSearch</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span>
      <span class="token operator">/</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>ul<span class="token operator">&gt;</span>
        <span class="token punctuation">{</span>filteredTodos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>todo <span class="token operator">=&gt;</span> <span class="token punctuation">(</span>
          <span class="token operator">&lt;</span>li key<span class="token operator">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span><span class="token operator">&gt;</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>li<span class="token operator">&gt;</span>
        <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>ul<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>This works, but notice what happens when you type in the search box or add a new todo: React reruns the entire component, including the <code>todos.filter()</code> call.</p><p>Now imagine you have hundreds or thousands of todos, or that the filter operation involves heavier logic. You don&rsquo;t want to run that unnecessarily on every render.</p><p>Here&rsquo;s where <code>useMemo</code> helps:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">function</span> <span class="token function">TodoApp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>search<span class="token punctuation">,</span> setSearch<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>todos<span class="token punctuation">,</span> setTodos<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
    <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> <span class="token string">"Buy groceries"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> <span class="token string">"Read a book"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> <span class="token string">"Go for a walk"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> filteredTodos <span class="token operator">=</span> <span class="token function">useMemo</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Filtering todos..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> todos<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>todo <span class="token operator">=&gt;</span>
      todo<span class="token punctuation">.</span>text<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span>search<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>todos<span class="token punctuation">,</span> search<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>input
        type<span class="token operator">=</span><span class="token string">"text"</span>
        placeholder<span class="token operator">=</span><span class="token string">"Search todos..."</span>
        value<span class="token operator">=</span><span class="token punctuation">{</span>search<span class="token punctuation">}</span>
        onChange<span class="token operator">=</span><span class="token punctuation">{</span>e <span class="token operator">=&gt;</span> <span class="token function">setSearch</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span>
      <span class="token operator">/</span><span class="token operator">&gt;</span>

      <span class="token operator">&lt;</span>ul<span class="token operator">&gt;</span>
        <span class="token punctuation">{</span>filteredTodos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>todo <span class="token operator">=&gt;</span> <span class="token punctuation">(</span>
          <span class="token operator">&lt;</span>li key<span class="token operator">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span><span class="token operator">&gt;</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>li<span class="token operator">&gt;</span>
        <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>ul<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Now, the filter only runs when either <code>todos</code> or <code>search</code> changes. If you trigger a re-render for any other reason (say, toggling a modal or updating unrelated state higher up in the tree), React will reuse the cached filtered list from the previous render.</p><p><code>useMemo</code> shines in situations like this when you&rsquo;re doing expensive or repetitive calculations during render that don&rsquo;t need to run every single time. It&rsquo;s not about squeezing out microseconds; it&rsquo;s about keeping your renders predictable and efficient as your app scales.</p><p>In this todo example, the difference is subtle, but in a real-world app where filtering, sorting or formatting can get complex, memoization can save a noticeable amount of work.</p><h3>useCallback: Memoizing Functions for Stability</h3><p>If <code>useMemo</code> helps React remember values, then `useCallback helps React remember functions.</p><p>At first,this might sound unnecessary&mdash;after all, functions are cheap to create, right? But in React, passing functions down as props can sometimes cause subtle and frustrating re-renders that you don&rsquo;t expect.</p><p>The <code>useCallback()</code> hook is one of React&rsquo;s built-in tools for optimizing re-renders. Its job is simple but powerful&mdash;it lets React remember your function definitions between renders, so they don&rsquo;t get recreated every single time your component reruns.</p><p>In short, it memoizes the function itself.</p><p>Syntax:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> memoizedFunction <span class="token operator">=</span> <span class="token function">useCallback</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token comment">// Your logic here</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>dependency1<span class="token punctuation">,</span> dependency2<span class="token punctuation">,</span> <span class="token operator">...</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The <code>useCallback()</code> hook takes two arguments:</p><ol><li><strong>A function to memoize:</strong> This is the function you want React to remember. It can take any arguments and return any value.</li><li><strong>A dependency array:</strong> This lists every reactive value (state, props or variables) used inside that function. React will only recreate the function if one of those dependencies changes between renders.</li></ol><p>Here&rsquo;s what happens under the hood:</p><ul><li>On the first render, React creates and returns the function.</li><li>On later renders, React checks if any dependencies have changed.</li></ul><p>This simple mechanism keeps the function reference stable across renders, which is exactly what you want when passing callbacks to memoized child components.</p><p>Remember: Since <code>useCallback</code> is a hook, it must follow the rules of hooks. Call it only at the top level of a React component or custom hook, never inside loops, conditionals or nested functions.</p><h3>Practical Example: Preventing Unnecessary Re-renders</h3><p>Let&rsquo;s bring this to life with a practical example.</p><p>Suppose you&rsquo;re building a simple todo app that displays a list of tasks, with the ability to mark each one as done or undone.</p><p>Here&rsquo;s the initial setup:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> TodoItem <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">memo</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">{</span> todo<span class="token punctuation">,</span> onChange <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`Rendering </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>todo<span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> `</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>span style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> textDecoration<span class="token punctuation">:</span> todo<span class="token punctuation">.</span>done <span class="token operator">?</span> <span class="token string">"line-through"</span> <span class="token punctuation">:</span> <span class="token string">"none"</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
        <span class="token punctuation">{</span>todo<span class="token punctuation">.</span>name<span class="token punctuation">}</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">onChange</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
        <span class="token punctuation">{</span>todo<span class="token punctuation">.</span>done <span class="token operator">?</span> <span class="token string">"Undone"</span> <span class="token punctuation">:</span> <span class="token string">"Done"</span><span class="token punctuation">}</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> demoTodos <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"Todo 1"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"Todo 2"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"Todo 3"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"Todo 4"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">TodoList</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>todos<span class="token punctuation">,</span> setTodos<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span>demoTodos<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">function</span> <span class="token function">toggleTodo</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">setTodos</span><span class="token punctuation">(</span>prevTodos <span class="token operator">=&gt;</span>
      prevTodos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>todo <span class="token operator">=&gt;</span>
        todo<span class="token punctuation">.</span>id <span class="token operator">===</span> id <span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token operator">...</span>todo<span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token operator">!</span>todo<span class="token punctuation">.</span>done <span class="token punctuation">}</span> <span class="token punctuation">:</span> todo
      <span class="token punctuation">)</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>h2<span class="token operator">&gt;</span>Today&rsquo;s Todos<span class="token operator">&lt;</span><span class="token operator">/</span>h2<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>ul<span class="token operator">&gt;</span>
        <span class="token punctuation">{</span>todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>todo <span class="token operator">=&gt;</span> <span class="token punctuation">(</span>
          <span class="token operator">&lt;</span>li key<span class="token operator">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span><span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>TodoItem todo<span class="token operator">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span>toggleTodo<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
          <span class="token operator">&lt;</span><span class="token operator">/</span>li<span class="token operator">&gt;</span>
        <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>ul<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> TodoList<span class="token punctuation">;</span>
</code></pre><p>The <code>TodoItem</code> component is wrapped in <code>React.memo</code>, meaning it shouldn&rsquo;t re-render unless its props change. But if you try this out, you&rsquo;ll notice something strange&mdash;clicking the button causes every TodoItem to re-render, not just the one you toggled:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/react-todo-demo.gif?sfvrsn=5d7b5624_2" alt="Demo 1" /></p><h3 id="why">Why?</h3><p>Because each time <code>TodoList</code> re-renders, React creates a brand-new <code>toggleTodo</code> function. From React&rsquo;s perspective, that means the <code>onChange</code> prop on every child is now different, even if the logic is the same, so <code>React.memo</code> decides to re-render everything.</p><p>That&rsquo;s exactly the kind of subtle inefficiency <code>useCallback</code> fixes.</p><h3 id="fixing-it-with-usecallback">Fixing it with useCallback</h3><p>Let&rsquo;s wrap the <code>toggleTodo</code> function in <code>useCallback</code> to make its reference stable:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> useState<span class="token punctuation">,</span> useCallback <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> TodoItem <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">memo</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">{</span> todo<span class="token punctuation">,</span> onChange <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`Rendering </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>todo<span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> `</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>span style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> textDecoration<span class="token punctuation">:</span> todo<span class="token punctuation">.</span>done <span class="token operator">?</span> <span class="token string">"line-through"</span> <span class="token punctuation">:</span> <span class="token string">"none"</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
        <span class="token punctuation">{</span>todo<span class="token punctuation">.</span>name<span class="token punctuation">}</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">onChange</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
        <span class="token punctuation">{</span>todo<span class="token punctuation">.</span>done <span class="token operator">?</span> <span class="token string">"Undone"</span> <span class="token punctuation">:</span> <span class="token string">"Done"</span><span class="token punctuation">}</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> demoTodos <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"Todo 1"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"Todo 2"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"Todo 3"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"Todo 4"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token function-variable function">TodoList</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>todos<span class="token punctuation">,</span> setTodos<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span>demoTodos<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> toggleTodo <span class="token operator">=</span> <span class="token function">useCallback</span><span class="token punctuation">(</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">setTodos</span><span class="token punctuation">(</span>prevTodos <span class="token operator">=&gt;</span>
      prevTodos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>todo <span class="token operator">=&gt;</span>
        todo<span class="token punctuation">.</span>id <span class="token operator">===</span> id <span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token operator">...</span>todo<span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token operator">!</span>todo<span class="token punctuation">.</span>done <span class="token punctuation">}</span> <span class="token punctuation">:</span> todo
      <span class="token punctuation">)</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>h2<span class="token operator">&gt;</span>Today&rsquo;s Todos<span class="token operator">&lt;</span><span class="token operator">/</span>h2<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>ul<span class="token operator">&gt;</span>
        <span class="token punctuation">{</span>todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>todo <span class="token operator">=&gt;</span> <span class="token punctuation">(</span>
          <span class="token operator">&lt;</span>li key<span class="token operator">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span><span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>TodoItem todo<span class="token operator">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span>toggleTodo<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
          <span class="token operator">&lt;</span><span class="token operator">/</span>li<span class="token operator">&gt;</span>
        <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>ul<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> TodoList<span class="token punctuation">;</span>
</code></pre><p>Now, the <code>toggleTodo</code> function keeps the same reference between renders because its dependency array (<code>[]</code>) is empty. React creates it once and reuses it as long as the component stays mounted.</p><p>Since <code>TodoItem</code> receives a stable <code>onChange</code> prop, <code>React.memo</code> can finally do its job&mdash;only the toggled TodoItem re-renders, not the entire list.</p><p>In a small Todo app, this might feel like a micro-optimization. But in a real app, think of dozens of components, large lists or complex trees. Stabilizing your callbacks can prevent entire subtrees from re-rendering unnecessarily.</p><p>That&rsquo;s not just about performance; it&rsquo;s about keeping your app predictable, scalable and smooth.</p><p>Here&rsquo;s the <a target="_blank" href="https://codesandbox.io/p/sandbox/usecallback-3dppld">CodeSandbox demo</a> if you want to play around with it. Try adding features like add, delete or edit, and see how <code>useCallback</code> helps control re-renders as your app grows.</p><h2 id="when-and-when-not-to--memoize">When (and When Not) to Memoize</h2><p>Memoization is powerful, but it&rsquo;s not free. Every memoized value or component adds a bit of overhead. React needs to compare dependencies, store results and decide whether to reuse or recompute. Overusing it can actually make things slower or harder to read.</p><h3>Use Memoization When:</h3><ul><li>A component re-renders often with identical props.</li><li>You&rsquo;re doing expensive computations (sorting, filtering, formatting).</li><li>You&rsquo;re passing callbacks to deeply nested children wrapped in <code>React.memo</code></li></ul><h3>Avoid Memoization When:</h3><ul><li>The component is small and cheap to render.</li><li>Props change frequently anyway.</li><li>You&rsquo;re just memoizing out of habit.</li></ul><p>In short: <strong>Measure first, optimize second.</strong> Don&rsquo;t sprinkle memoization everywhere &ldquo;just in case.&rdquo;</p><h2 id="react-19-rethinking-memoization">React 19: Rethinking Memoization</h2><p>Here&rsquo;s where things get interesting. React 19 introduces several architectural improvements that make manual memoization far less critical than before. Under the hood, React&rsquo;s new compiler can automatically memoize components and hooks at build time&mdash;analyzing your component&rsquo;s dependencies and optimizing re-renders intelligently.</p><p>That means in most cases, you no longer need to reach for <code>React.memo</code>, <code>useMemo</code> or <code>useCallback</code> unless you&rsquo;re dealing with very specific edge cases.</p><p>Here&rsquo;s what changes:</p><ul><li><strong>Automatic memoization:</strong> The React compiler now detects pure components and automatically memoizes them, skipping re-renders when inputs haven&rsquo;t changed.</li><li><strong>Smarter dependency tracking:</strong> Instead of relying on manual dependency arrays, React can track dependencies automatically, reducing human error and cleanup code.</li><li><strong>Simplified mental model:</strong> You can focus on writing clean, declarative code, and React handles the optimization behind the scenes.</li></ul><p>In practice, this means your React 19 codebase becomes simpler and less noisy. Hooks like <code>useCallback</code> and <code>useMemo</code> are still available for advanced control, but they&rsquo;re no longer the first thing you reach for&mdash;React just <em>does the right thing</em> by default.</p><h2 id="final-thoughts">Final Thoughts</h2><p>Memoization in React is all about efficiency, caching results or function references to avoid redundant work.</p><p>Before React 19, we relied heavily on <code>React.memo</code>, <code>useMemo</code> and <code>useCallback</code> to manage this manually. But with React 19&rsquo;s new compiler, much of that optimization happens automatically.</p><p>Still, knowing how memoization works gives you the mental model to understand what React is doing behind the scenes and when to step in yourself. Because even in the new world of auto-optimization, the best React developers understand the &ldquo;why,&rdquo; not just the &ldquo;what.&rdquo;</p><h3 id="further-reading">Further Reading</h3><ul><li><a target="_blank" href="https://www.telerik.com/blogs/react-basics-how-use-react-usecallback-effectively">React Basics: How to Use React useCallback Effectively</a></li><li><a target="_blank" href="https://www.telerik.com/blogs/learn-how-usememo-hook-once-all">Learn How to Use the useMemo Hook Once and for All</a></li><li><a target="_blank" href="https://www.telerik.com/blogs/how-optimize-code-react-compiler-beta">How to Optimize Your Code with React Compiler (Still in Beta)</a></li><li><a target="_blank" href="https://react.dev/reference/react/memo">React memo</a></li></ul><img src="https://feeds.telerik.com/link/23056/17268597.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:ee9c0569-ac10-432d-b5d9-c3543cd39ca7</id>
    <title type="text">Exploring the AI-Powered KendoReact Smart Grid</title>
    <summary type="text">The KendoReact SmartGrid brings AI prompting capabilities to your favorite enterprise-grade component.v</summary>
    <published>2026-01-21T17:56:47Z</published>
    <updated>2026-04-23T22:50:00Z</updated>
    <author>
      <name>Hassan Djirdeh </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23056/17259438/exploring-ai-powered-kendoreact-smart-grid"/>
    <content type="text"><![CDATA[<p><span class="featured">The KendoReact SmartGrid brings AI prompting capabilities to your favorite enterprise-grade component.</span></p><p>Working with large datasets in web applications can involve repetitive tasks, such as manually configuring filters, setting sorting rules or grouping data in multiple ways to find the information you need. While traditional data grids (like the Progress <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/grid">KendoReact Data Grid</a>) provide the tools to accomplish these operations, they require users to understand the grid&rsquo;s interface and manually configure each step of each operation.</p><p>What if our data grid could understand natural language commands? What if we could ask it to &ldquo;show only failed transactions over $500&rdquo; or &ldquo;group customers by region and sort by revenue&rdquo;? This is exactly what the new <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/grid/smart">KendoReact SmartGrid</a> offers.</p><h2 id="kendoreact-smartgrid">KendoReact SmartGrid</h2><p>The KendoReact SmartGrid enhances the traditional KendoReact DataGrid with AI-powered capabilities that enable users to interact with data using natural language. Instead of clicking through menus and manually configuring filters, users can describe what they want to see, and the AI assistant translates those requests into grid operations.</p><p>The SmartGrid maintains all the powerful features of the standard grid (sorting, filtering, grouping, etc.) while adding an intelligent layer that interprets user intent and automatically applies the appropriate data operations.</p><p>Let&rsquo;s start with a basic implementation to see the SmartGrid in action:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  Grid<span class="token punctuation">,</span>
  GridColumn<span class="token punctuation">,</span>
  GridToolbar<span class="token punctuation">,</span>
  GridToolbarAIAssistant<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-grid'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> filterIcon <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-svg-icons'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">App</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> transactions <span class="token operator">=</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
      customerName<span class="token punctuation">:</span> <span class="token string">'Acme Corp'</span><span class="token punctuation">,</span>
      amount<span class="token punctuation">:</span> <span class="token number">1250.0</span><span class="token punctuation">,</span>
      currency<span class="token punctuation">:</span> <span class="token string">'USD'</span><span class="token punctuation">,</span>
      status<span class="token punctuation">:</span> <span class="token string">'Completed'</span><span class="token punctuation">,</span>
      transType<span class="token punctuation">:</span> <span class="token string">'Deposit'</span><span class="token punctuation">,</span>
      transDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">'2024-10-15'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span>
      customerName<span class="token punctuation">:</span> <span class="token string">'Tech Solutions'</span><span class="token punctuation">,</span>
      amount<span class="token punctuation">:</span> <span class="token number">450.0</span><span class="token punctuation">,</span>
      currency<span class="token punctuation">:</span> <span class="token string">'EUR'</span><span class="token punctuation">,</span>
      status<span class="token punctuation">:</span> <span class="token string">'Failed'</span><span class="token punctuation">,</span>
      transType<span class="token punctuation">:</span> <span class="token string">'Withdrawal'</span><span class="token punctuation">,</span>
      transDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">'2024-10-16'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span>
      customerName<span class="token punctuation">:</span> <span class="token string">'Global Industries'</span><span class="token punctuation">,</span>
      amount<span class="token punctuation">:</span> <span class="token number">2100.0</span><span class="token punctuation">,</span>
      currency<span class="token punctuation">:</span> <span class="token string">'USD'</span><span class="token punctuation">,</span>
      status<span class="token punctuation">:</span> <span class="token string">'Completed'</span><span class="token punctuation">,</span>
      transType<span class="token punctuation">:</span> <span class="token string">'Deposit'</span><span class="token punctuation">,</span>
      transDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">'2024-10-17'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> <span class="token number">4</span><span class="token punctuation">,</span>
      customerName<span class="token punctuation">:</span> <span class="token string">'StartUp Inc'</span><span class="token punctuation">,</span>
      amount<span class="token punctuation">:</span> <span class="token number">850.0</span><span class="token punctuation">,</span>
      currency<span class="token punctuation">:</span> <span class="token string">'GBP'</span><span class="token punctuation">,</span>
      status<span class="token punctuation">:</span> <span class="token string">'Pending'</span><span class="token punctuation">,</span>
      transType<span class="token punctuation">:</span> <span class="token string">'Withdrawal'</span><span class="token punctuation">,</span>
      transDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">'2024-10-18'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
      customerName<span class="token punctuation">:</span> <span class="token string">'Enterprise Co'</span><span class="token punctuation">,</span>
      amount<span class="token punctuation">:</span> <span class="token number">3200.0</span><span class="token punctuation">,</span>
      currency<span class="token punctuation">:</span> <span class="token string">'USD'</span><span class="token punctuation">,</span>
      status<span class="token punctuation">:</span> <span class="token string">'Completed'</span><span class="token punctuation">,</span>
      transType<span class="token punctuation">:</span> <span class="token string">'Deposit'</span><span class="token punctuation">,</span>
      transDate<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">'2024-10-19'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span>
      <span class="token attr-name">autoProcessData</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token boolean">true</span><span class="token punctuation">}</span></span>
      <span class="token attr-name">dataItemKey</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>id<span class="token punctuation">"</span></span>
      <span class="token attr-name">data</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>transactions<span class="token punctuation">}</span></span>
      <span class="token attr-name">sortable</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token boolean">true</span><span class="token punctuation">}</span></span>
      <span class="token attr-name">groupable</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token boolean">true</span><span class="token punctuation">}</span></span>
      <span class="token attr-name">pageable</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token boolean">true</span><span class="token punctuation">}</span></span>
      <span class="token attr-name">columnMenuIcon</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>filterIcon<span class="token punctuation">}</span></span>
    <span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridToolbar</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridToolbarAIAssistant</span>
          <span class="token attr-name">requestUrl</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>https://demos.telerik.com/service/v2/ai/grid/smart-state<span class="token punctuation">"</span></span>
          <span class="token attr-name">promptPlaceHolder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Filter, sort or group with AI<span class="token punctuation">"</span></span>
          <span class="token attr-name">suggestionsList</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">[</span>
            <span class="token string">'Sort by amount descending'</span><span class="token punctuation">,</span>
            <span class="token string">'Show only completed transactions'</span><span class="token punctuation">,</span>
            <span class="token string">'Group by transaction type'</span><span class="token punctuation">,</span>
            <span class="token string">'Filter where currency is USD'</span><span class="token punctuation">,</span>
          <span class="token punctuation">]</span><span class="token punctuation">}</span></span>
          <span class="token attr-name">enableSpeechToText</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token boolean">true</span><span class="token punctuation">}</span></span>
        <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>GridToolbar</span><span class="token punctuation">&gt;</span></span>

      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridColumn</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>customerName<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Customer Name<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token number">180</span><span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridColumn</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>amount<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Amount<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token number">120</span><span class="token punctuation">}</span></span> <span class="token attr-name">format</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{0:c2}<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridColumn</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>currency<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Currency<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token number">100</span><span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridColumn</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>status<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Status<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token number">120</span><span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridColumn</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>transType<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Type<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token number">120</span><span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridColumn</span>
        <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>transDate<span class="token punctuation">"</span></span>
        <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Date<span class="token punctuation">"</span></span>
        <span class="token attr-name">width</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token number">140</span><span class="token punctuation">}</span></span>
        <span class="token attr-name">format</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{0:MM/dd/yyyy}<span class="token punctuation">"</span></span>
      <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span>
</code></pre><p>In the example above, we&rsquo;ve created a transaction grid using the AI-powered toolbar assistant. The <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/grid/api/gridtoolbaraiassistant">GridToolbarAIAssistant</a> component provides a natural language interface that lets users type commands like &ldquo;show only completed transactions&rdquo; or &ldquo;sort by amount descending,&rdquo; and the AI automatically applies those operations to the grid.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/kendo-smart-grid-basic.gif?sfvrsn=a554782d_2" alt="" /></p><p>The <code>autoProcessData</code> prop is key here in the above example. It enables the grid to automatically handle state updates when AI operations are applied, eliminating the need for manual state management in simple scenarios.</p><blockquote><p>The SmartGrid is part of KendoReact Premium, <a target="_blank" href="https://www.telerik.com/kendo-react-ui#two-paths-forward">an enterprise-grade UI library with 120+ components</a>. The AI features demonstrated here use a Telerik-hosted service for demonstration purposes. For production applications, you&rsquo;ll want to implement your own AI service tailored to your specific domain and data requirements.</p></blockquote><h2 id="voice-input-support">Voice Input Support</h2><p>A cool feature of the SmartGrid is its support for speech-to-text input. By setting <code>enableSpeechToText={true}</code> on the <code>GridToolbarAIAssistant</code>, users can speak their commands directly instead of typing them.</p><p>To use voice input, users click the microphone icon in the AI assistant and speak their command. The grid processes spoken commands the same way as typed text, so commands like &ldquo;show only completed transactions&rdquo; work just as seamlessly.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/kendo-smart-grid-voice.gif?sfvrsn=d6300b03_2" alt="" /></p><p>The voice input feature uses the browser&rsquo;s native Web Speech API, so it works across modern browsers without additional dependencies or setup.</p><h2 id="tracking-operations-with-controlled-integration">Tracking Operations with Controlled Integration</h2><p>While <code>autoProcessData</code> works great for simple scenarios, we may need more control over how AI operations are applied to our grid. For example, we can log user interactions, validate AI suggestions before applying them or display an operation history to users.</p><p>The controlled approach gives us this flexibility through the <code>onResponseSuccess</code> callback:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> process <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-data-query'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  Grid<span class="token punctuation">,</span>
  GridColumn<span class="token punctuation">,</span>
  GridToolbar<span class="token punctuation">,</span>
  GridToolbarAIAssistant<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-grid'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">App</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>dataState<span class="token punctuation">,</span> setDataState<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    skip<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
    take<span class="token punctuation">:</span> <span class="token number">10</span><span class="token punctuation">,</span>
    sort<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    filter<span class="token punctuation">:</span> undefined<span class="token punctuation">,</span>
    group<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> <span class="token punctuation">[</span>outputs<span class="token punctuation">,</span> setOutputs<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> aiAssistantRef <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useRef</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> transactions <span class="token operator">=</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
      customerName<span class="token punctuation">:</span> <span class="token string">'Acme Corp'</span><span class="token punctuation">,</span>
      amount<span class="token punctuation">:</span> <span class="token number">1250.0</span><span class="token punctuation">,</span>
      status<span class="token punctuation">:</span> <span class="token string">'Completed'</span><span class="token punctuation">,</span>
      currency<span class="token punctuation">:</span> <span class="token string">'USD'</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span>
      customerName<span class="token punctuation">:</span> <span class="token string">'Tech Solutions'</span><span class="token punctuation">,</span>
      amount<span class="token punctuation">:</span> <span class="token number">450.0</span><span class="token punctuation">,</span>
      status<span class="token punctuation">:</span> <span class="token string">'Failed'</span><span class="token punctuation">,</span>
      currency<span class="token punctuation">:</span> <span class="token string">'EUR'</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span>
      customerName<span class="token punctuation">:</span> <span class="token string">'Global Industries'</span><span class="token punctuation">,</span>
      amount<span class="token punctuation">:</span> <span class="token number">2100.0</span><span class="token punctuation">,</span>
      status<span class="token punctuation">:</span> <span class="token string">'Completed'</span><span class="token punctuation">,</span>
      currency<span class="token punctuation">:</span> <span class="token string">'USD'</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> <span class="token number">4</span><span class="token punctuation">,</span>
      customerName<span class="token punctuation">:</span> <span class="token string">'StartUp Inc'</span><span class="token punctuation">,</span>
      amount<span class="token punctuation">:</span> <span class="token number">850.0</span><span class="token punctuation">,</span>
      status<span class="token punctuation">:</span> <span class="token string">'Pending'</span><span class="token punctuation">,</span>
      currency<span class="token punctuation">:</span> <span class="token string">'GBP'</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
      customerName<span class="token punctuation">:</span> <span class="token string">'Enterprise Co'</span><span class="token punctuation">,</span>
      amount<span class="token punctuation">:</span> <span class="token number">3200.0</span><span class="token punctuation">,</span>
      status<span class="token punctuation">:</span> <span class="token string">'Completed'</span><span class="token punctuation">,</span>
      currency<span class="token punctuation">:</span> <span class="token string">'USD'</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> <span class="token function-variable function">handleResponseSuccess</span> <span class="token operator">=</span> <span class="token punctuation">(</span>response<span class="token punctuation">,</span> promptMessage<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>response <span class="token operator">&amp;&amp;</span> response<span class="token punctuation">.</span>data<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// Apply AI-suggested operations to grid state</span>
      <span class="token keyword">const</span> newState <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token operator">...</span>dataState <span class="token punctuation">}</span><span class="token punctuation">;</span>

      <span class="token keyword">if</span> <span class="token punctuation">(</span>response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>sort<span class="token punctuation">)</span> newState<span class="token punctuation">.</span>sort <span class="token operator">=</span> response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>sort<span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>filter<span class="token punctuation">)</span> newState<span class="token punctuation">.</span>filter <span class="token operator">=</span> response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>filter<span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>group<span class="token punctuation">)</span> newState<span class="token punctuation">.</span>group <span class="token operator">=</span> response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>group<span class="token punctuation">;</span>

      <span class="token function">setDataState</span><span class="token punctuation">(</span>newState<span class="token punctuation">)</span><span class="token punctuation">;</span>

      <span class="token comment">// Track the operation in history</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>messages<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> newOutput <span class="token operator">=</span> <span class="token punctuation">{</span>
          id<span class="token punctuation">:</span> outputs<span class="token punctuation">.</span>length <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span>
          prompt<span class="token punctuation">:</span> promptMessage<span class="token punctuation">,</span>
          responseContent<span class="token punctuation">:</span> response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>messages<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
        <span class="token function">setOutputs</span><span class="token punctuation">(</span><span class="token punctuation">[</span>newOutput<span class="token punctuation">,</span> <span class="token operator">...</span>outputs<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    aiAssistantRef<span class="token punctuation">.</span>current<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">hide</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> processedData <span class="token operator">=</span> <span class="token function">process</span><span class="token punctuation">(</span>transactions<span class="token punctuation">,</span> dataState<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>Grid
      dataItemKey<span class="token operator">=</span><span class="token string">"id"</span>
      data<span class="token operator">=</span><span class="token punctuation">{</span>processedData<span class="token punctuation">.</span>data<span class="token punctuation">}</span>
      total<span class="token operator">=</span><span class="token punctuation">{</span>processedData<span class="token punctuation">.</span>total<span class="token punctuation">}</span>
      sortable<span class="token operator">=</span><span class="token punctuation">{</span><span class="token boolean">true</span><span class="token punctuation">}</span>
      sort<span class="token operator">=</span><span class="token punctuation">{</span>dataState<span class="token punctuation">.</span>sort<span class="token punctuation">}</span>
      onSortChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setDataState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token operator">...</span>dataState<span class="token punctuation">,</span> sort<span class="token punctuation">:</span> e<span class="token punctuation">.</span>sort <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
      filterable<span class="token operator">=</span><span class="token punctuation">{</span><span class="token boolean">true</span><span class="token punctuation">}</span>
      filter<span class="token operator">=</span><span class="token punctuation">{</span>dataState<span class="token punctuation">.</span>filter<span class="token punctuation">}</span>
      onFilterChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setDataState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token operator">...</span>dataState<span class="token punctuation">,</span> filter<span class="token punctuation">:</span> e<span class="token punctuation">.</span>filter <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
      groupable<span class="token operator">=</span><span class="token punctuation">{</span><span class="token boolean">true</span><span class="token punctuation">}</span>
      group<span class="token operator">=</span><span class="token punctuation">{</span>dataState<span class="token punctuation">.</span>group<span class="token punctuation">}</span>
      onGroupChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setDataState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token operator">...</span>dataState<span class="token punctuation">,</span> group<span class="token punctuation">:</span> e<span class="token punctuation">.</span>group <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
      pageable<span class="token operator">=</span><span class="token punctuation">{</span><span class="token boolean">true</span><span class="token punctuation">}</span>
      skip<span class="token operator">=</span><span class="token punctuation">{</span>dataState<span class="token punctuation">.</span>skip<span class="token punctuation">}</span>
      take<span class="token operator">=</span><span class="token punctuation">{</span>dataState<span class="token punctuation">.</span>take<span class="token punctuation">}</span>
      onPageChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
        <span class="token function">setDataState</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
          <span class="token operator">...</span>dataState<span class="token punctuation">,</span>
          skip<span class="token punctuation">:</span> e<span class="token punctuation">.</span>page<span class="token punctuation">.</span>skip<span class="token punctuation">,</span>
          take<span class="token punctuation">:</span> e<span class="token punctuation">.</span>page<span class="token punctuation">.</span>take<span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token operator">&gt;</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridToolbar</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridToolbarAIAssistant</span>
          <span class="token attr-name">ref</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>aiAssistantRef<span class="token punctuation">}</span></span>
          <span class="token attr-name">requestUrl</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>https://demos.telerik.com/service/v2/ai/grid/smart-state<span class="token punctuation">"</span></span>
          <span class="token attr-name">onResponseSuccess</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleResponseSuccess<span class="token punctuation">}</span></span>
          <span class="token attr-name">outputs</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>outputs<span class="token punctuation">}</span></span>
          <span class="token attr-name">promptPlaceHolder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Filter, sort or group with AI<span class="token punctuation">"</span></span>
        <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>GridToolbar</span><span class="token punctuation">&gt;</span></span>

      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridColumn</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>customerName<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Customer<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token number">180</span><span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridColumn</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>amount<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Amount<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token number">120</span><span class="token punctuation">}</span></span> <span class="token attr-name">format</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{0:c2}<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridColumn</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>status<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Status<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token number">120</span><span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>GridColumn</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>currency<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Currency<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token number">100</span><span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span>
</code></pre><p>In this controlled approach, we explicitly manage the grid&rsquo;s state and intercept AI responses via <code>onResponseSuccess</code>. This allows us to:</p><ul><li><strong>Validate AI suggestions</strong> before applying them to the grid.</li><li><strong>Log user interactions</strong> and AI operations for analytics or debugging.</li><li><strong>Display operation history</strong> through the <code>outputs</code> prop, giving users transparency into what commands they&rsquo;ve issued.</li></ul><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/kendo-smart-grid-controlled.gif?sfvrsn=b399003_2" alt="" /></p><p>The <code>outputs</code> prop displays a history of AI operations, helping users understand how their natural language requests were interpreted and what operations were performed on the grid.</p><h2 id="wrap-up">Wrap-up</h2><p>The KendoReact SmartGrid brings AI-powered capabilities to data grids, making complex data operations accessible through natural language. By simply describing what they want to see, users can filter, sort and group data without needing to understand the intricacies of the grid interface.</p><p>For more details on implementing the SmartGrid and exploring its capabilities, check out the official documentation:</p><ul><li><a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/grid/smart">KendoReact Smart DataGrid Overview</a></li><li><a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/grid">KendoReact Grid Documentation</a></li></ul><p>And to try it for yourself, download the 30-day free trial:</p><p><a target="_blank" href="https://www.telerik.com/try/kendo-react-ui" class="Btn">Try Now</a></p><img src="https://feeds.telerik.com/link/23056/17259438.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:3569d367-3697-4c90-bd8d-d44bf89b92f0</id>
    <title type="text">KendoReact Internationalization</title>
    <summary type="text">The React Internationalization component package can help translate your app’s numbers and dates into regionally appropriate formats.</summary>
    <published>2026-01-12T19:55:38Z</published>
    <updated>2026-04-23T22:50:00Z</updated>
    <author>
      <name>Hassan Djirdeh </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23056/17251907/kendoreact-internationalization"/>
    <content type="text"><![CDATA[<p><span class="featured">The React Internationalization component package can help translate your app&rsquo;s numbers and dates into regionally appropriate formats.</span></p><p>When building applications for users around the world, displaying data in familiar formats is important. A date like &ldquo;3/4/2024&rdquo; might mean March 4 to Americans but April 3 to Europeans. Similarly, the number &ldquo;1,234.56&rdquo; uses different separators in different countries; some use commas for thousands and periods for decimals, while others do the opposite. This is where <strong>internationalization</strong> comes in.</p><p>In this article, we&rsquo;ll explore the Progress <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/intl/i18n">KendoReact Internationalization</a> package and see how it handles the parsing and formatting of dates and numbers according to different conventions.</p><blockquote><p>The KendoReact Internationalization package is part of <a target="_blank" href="https://www.telerik.com/kendo-react-ui">KendoReact</a>, an enterprise-grade UI library with more than 120 components for building polished, performant apps.</p></blockquote><h2 id="internationalization-vs.-localization">Internationalization vs. Localization</h2><p>Before we dive in, let&rsquo;s clarify the difference between <em>internationalization</em> and <em>localization</em>, as these terms are often used interchangeably but can serve distinct purposes:</p><ul><li><strong>Internationalization</strong> focuses on parsing and formatting dates and numbers according to locale-specific rules. It makes &ldquo;1234.56&rdquo; display as &ldquo;1.234,56&rdquo; in Germany or dates follow the DD/MM/YYYY format in the UK.</li><li><strong>Localization</strong> handles translating UI text and supporting right-to-left (RTL) layouts for languages like Arabic. It sets button labels, error messages and other interface text in the user&rsquo;s preferred language.</li></ul><blockquote><p>For an introduction into localization and the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/intl/l10n">KendoReact Localization</a> package, check out our article on <a target="_blank" href="https://www.telerik.com" data-sf-ec-immutable="">Getting Started with KendoReact Localization</a>.</p></blockquote><p>Together, these two packages provide the complete <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/intl">globalization</a> features of KendoReact. In this article, we&rsquo;ll focus exclusively on internationalization.</p><h2 id="kendoreact-internationalization">KendoReact Internationalization</h2><p>The KendoReact Internationalization package is built on the <a target="_blank" href="https://cldr.unicode.org/">Unicode Common Locale Data Repository (CLDR)</a>, which provides standardized locale data for hundreds of languages and regions. The React Internationalization package exports an <code>IntlProvider</code> component that supplies formatting and parsing capabilities throughout a React app&rsquo;s component tree.</p><h2 id="setting-up-internationalization">Setting Up Internationalization</h2><p>To get started, we&rsquo;ll need to install the package:</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">npm</span> <span class="token function">install</span> @progress/kendo-react-intl
</code></pre><p>For locales other than the default <code>en-US</code>, <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/intl/i18n/parsing-and-formatting#using-cldr-json-data">we&rsquo;ll also need CLDR data</a>, which can be found by installing the necessary packages:</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">npm</span> <span class="token function">install</span> cldr-core cldr-numbers-full cldr-dates-full
</code></pre><p>These packages contain the locale-specific formatting rules that the Internationalization package uses to format dates and numbers correctly.</p><h2 id="formatting-numbers">Formatting Numbers</h2><p>Let&rsquo;s start with a practical example of number formatting. Different locales format numbers differently; what appears as &ldquo;1,234.56&rdquo; in the US becomes &ldquo;1.234,56&rdquo; in Germany and &ldquo;1 234,56&rdquo; in France.</p><p>Here&rsquo;s how to format numbers for different locales using the <code>IntlProvider</code> and the <code>useInternationalization</code> hook:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  IntlProvider<span class="token punctuation">,</span>
  load<span class="token punctuation">,</span>
  useInternationalization<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-intl'</span><span class="token punctuation">;</span>

<span class="token comment">// Import CLDR data</span>
<span class="token keyword">import</span> likelySubtags <span class="token keyword">from</span> <span class="token string">'cldr-core/supplemental/likelySubtags.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> currencyData <span class="token keyword">from</span> <span class="token string">'cldr-core/supplemental/currencyData.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> weekData <span class="token keyword">from</span> <span class="token string">'cldr-core/supplemental/weekData.json'</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> enNumbers <span class="token keyword">from</span> <span class="token string">'cldr-numbers-full/main/en/numbers.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> enCurrencies <span class="token keyword">from</span> <span class="token string">'cldr-numbers-full/main/en/currencies.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> deNumbers <span class="token keyword">from</span> <span class="token string">'cldr-numbers-full/main/de/numbers.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> deCurrencies <span class="token keyword">from</span> <span class="token string">'cldr-numbers-full/main/de/currencies.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> esNumbers <span class="token keyword">from</span> <span class="token string">'cldr-numbers-full/main/es/numbers.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> esCurrencies <span class="token keyword">from</span> <span class="token string">'cldr-numbers-full/main/es/currencies.json'</span><span class="token punctuation">;</span>

<span class="token comment">// Load CLDR data</span>
<span class="token function">load</span><span class="token punctuation">(</span>
  likelySubtags<span class="token punctuation">,</span>
  currencyData<span class="token punctuation">,</span>
  weekData<span class="token punctuation">,</span>
  enNumbers<span class="token punctuation">,</span>
  enCurrencies<span class="token punctuation">,</span>
  deNumbers<span class="token punctuation">,</span>
  deCurrencies<span class="token punctuation">,</span>
  esNumbers<span class="token punctuation">,</span>
  esCurrencies
<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">NumberDisplay</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> value <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> intl <span class="token operator">=</span> <span class="token function">useInternationalization</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>strong</span><span class="token punctuation">&gt;</span></span>Standard format<span class="token punctuation">:</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>intl<span class="token punctuation">.</span><span class="token function">formatNumber</span><span class="token punctuation">(</span>value<span class="token punctuation">,</span> <span class="token string">'n2'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>strong</span><span class="token punctuation">&gt;</span></span>Currency format<span class="token punctuation">:</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>intl<span class="token punctuation">.</span><span class="token function">formatNumber</span><span class="token punctuation">(</span>value<span class="token punctuation">,</span> <span class="token string">'c'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>strong</span><span class="token punctuation">&gt;</span></span>Percentage<span class="token punctuation">:</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>intl<span class="token punctuation">.</span><span class="token function">formatNumber</span><span class="token punctuation">(</span>value <span class="token operator">/</span> <span class="token number">100</span><span class="token punctuation">,</span> <span class="token string">'p2'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">App</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> numberValue <span class="token operator">=</span> <span class="token number">1234.56</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h3</span><span class="token punctuation">&gt;</span></span><span class="token function">English</span> <span class="token punctuation">(</span>US<span class="token punctuation">)</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h3</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>IntlProvider</span> <span class="token attr-name">locale</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>NumberDisplay</span> <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>numberValue<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>IntlProvider</span><span class="token punctuation">&gt;</span></span>

      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h3</span><span class="token punctuation">&gt;</span></span><span class="token function">German</span> <span class="token punctuation">(</span>Germany<span class="token punctuation">)</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h3</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>IntlProvider</span> <span class="token attr-name">locale</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>de<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>NumberDisplay</span> <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>numberValue<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>IntlProvider</span><span class="token punctuation">&gt;</span></span>

      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h3</span><span class="token punctuation">&gt;</span></span><span class="token function">Spanish</span> <span class="token punctuation">(</span>Spain<span class="token punctuation">)</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h3</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>IntlProvider</span> <span class="token attr-name">locale</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>es<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>NumberDisplay</span> <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>numberValue<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>IntlProvider</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span>
</code></pre><p>In this example, we load the necessary CLDR data at the top of our file using the <code>load</code> function. Then, we wrap each section with an <code>IntlProvider</code> that specifies the locale. Inside the <code>NumberDisplay</code> component, we use the <code>useInternationalization</code> hook to access the internationalization service, which provides the <code>formatNumber</code> method.</p><p>The <code>formatNumber</code> method accepts a value and a format string. Common format strings include:</p><ul><li><code>'n2'</code> - number with two decimal places</li><li><code>'c'</code> - currency</li><li><code>'p2'</code> - percentage with two decimal places</li></ul><p>When we run this app, we see the same number value (<code>1234.56</code>) displayed in three different sections, each formatted according to its respective locale&rsquo;s conventions:</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2025/2025-12//kendoreact-internationalization-numbers.png" alt="" /></p><h2 id="formatting-dates">Formatting Dates</h2><p>Date formatting is equally important. The date November 6, 2000, can be written as &ldquo;11/6/2000&rdquo; in the US, &ldquo;06/11/2000&rdquo; in the UK or &ldquo;6.11.2000&rdquo; in Germany. Let&rsquo;s see how to handle these variations:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  IntlProvider<span class="token punctuation">,</span>
  load<span class="token punctuation">,</span>
  useInternationalization<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-intl'</span><span class="token punctuation">;</span>

<span class="token comment">// Import CLDR data</span>
<span class="token keyword">import</span> likelySubtags <span class="token keyword">from</span> <span class="token string">'cldr-core/supplemental/likelySubtags.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> weekData <span class="token keyword">from</span> <span class="token string">'cldr-core/supplemental/weekData.json'</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> enCaGregorian <span class="token keyword">from</span> <span class="token string">'cldr-dates-full/main/en/ca-gregorian.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> enTimeZoneNames <span class="token keyword">from</span> <span class="token string">'cldr-dates-full/main/en/timeZoneNames.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> deCaGregorian <span class="token keyword">from</span> <span class="token string">'cldr-dates-full/main/de/ca-gregorian.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> deTimeZoneNames <span class="token keyword">from</span> <span class="token string">'cldr-dates-full/main/de/timeZoneNames.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> esCaGregorian <span class="token keyword">from</span> <span class="token string">'cldr-dates-full/main/es/ca-gregorian.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> esTimeZoneNames <span class="token keyword">from</span> <span class="token string">'cldr-dates-full/main/es/timeZoneNames.json'</span><span class="token punctuation">;</span>

<span class="token comment">// Load CLDR data</span>
<span class="token function">load</span><span class="token punctuation">(</span>
  likelySubtags<span class="token punctuation">,</span>
  weekData<span class="token punctuation">,</span>
  enCaGregorian<span class="token punctuation">,</span>
  enTimeZoneNames<span class="token punctuation">,</span>
  deCaGregorian<span class="token punctuation">,</span>
  deTimeZoneNames<span class="token punctuation">,</span>
  esCaGregorian<span class="token punctuation">,</span>
  esTimeZoneNames
<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">DateDisplay</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> value <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> intl <span class="token operator">=</span> <span class="token function">useInternationalization</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>strong</span><span class="token punctuation">&gt;</span></span>Short date<span class="token punctuation">:</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>intl<span class="token punctuation">.</span><span class="token function">formatDate</span><span class="token punctuation">(</span>value<span class="token punctuation">,</span> <span class="token string">'d'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>strong</span><span class="token punctuation">&gt;</span></span>Long date<span class="token punctuation">:</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>intl<span class="token punctuation">.</span><span class="token function">formatDate</span><span class="token punctuation">(</span>value<span class="token punctuation">,</span> <span class="token string">'D'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>strong</span><span class="token punctuation">&gt;</span></span>Full date<span class="token punctuation">:</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>intl<span class="token punctuation">.</span><span class="token function">formatDate</span><span class="token punctuation">(</span>value<span class="token punctuation">,</span> <span class="token string">'EEEE, MMMM d, y'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">App</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> dateValue <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token number">2000</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// November 6th, 2000</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h3</span><span class="token punctuation">&gt;</span></span><span class="token function">English</span> <span class="token punctuation">(</span>US<span class="token punctuation">)</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h3</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>IntlProvider</span> <span class="token attr-name">locale</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>DateDisplay</span> <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>dateValue<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>IntlProvider</span><span class="token punctuation">&gt;</span></span>

      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h3</span><span class="token punctuation">&gt;</span></span><span class="token function">German</span> <span class="token punctuation">(</span>Germany<span class="token punctuation">)</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h3</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>IntlProvider</span> <span class="token attr-name">locale</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>de<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>DateDisplay</span> <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>dateValue<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>IntlProvider</span><span class="token punctuation">&gt;</span></span>

      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h3</span><span class="token punctuation">&gt;</span></span><span class="token function">Spanish</span> <span class="token punctuation">(</span>Spain<span class="token punctuation">)</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h3</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>IntlProvider</span> <span class="token attr-name">locale</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>es<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>DateDisplay</span> <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>dateValue<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>IntlProvider</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span>
</code></pre><p>The <code>formatDate</code> method works similarly to <code>formatNumber</code>, accepting a date value and a format string. Common format patterns include:</p><ul><li><code>'d'</code> - short date pattern</li><li><code>'D'</code> - long date pattern</li><li>Custom patterns like <code>'EEEE, MMMM d, y'</code> for full control</li></ul><p>Running this app displays the same date (November 6, 2000) formatted in three different ways across English, German and Spanish locales:</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2025/2025-12//kendoreact-internationalization-dates.png" alt="" /></p><h2 id="interactive-locale-switching">Interactive Locale Switching</h2><p>We&rsquo;ll now build a more interactive example that allows users to switch between locales dynamically. This demonstrates how the Internationalization package can adapt to user preferences in real time:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  IntlProvider<span class="token punctuation">,</span>
  load<span class="token punctuation">,</span>
  useInternationalization<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-intl'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> DropDownList <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-dropdowns'</span><span class="token punctuation">;</span>

<span class="token comment">// Import CLDR data</span>
<span class="token keyword">import</span> likelySubtags <span class="token keyword">from</span> <span class="token string">'cldr-core/supplemental/likelySubtags.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> currencyData <span class="token keyword">from</span> <span class="token string">'cldr-core/supplemental/currencyData.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> weekData <span class="token keyword">from</span> <span class="token string">'cldr-core/supplemental/weekData.json'</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> enNumbers <span class="token keyword">from</span> <span class="token string">'cldr-numbers-full/main/en/numbers.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> enCurrencies <span class="token keyword">from</span> <span class="token string">'cldr-numbers-full/main/en/currencies.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> enCaGregorian <span class="token keyword">from</span> <span class="token string">'cldr-dates-full/main/en/ca-gregorian.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> enTimeZoneNames <span class="token keyword">from</span> <span class="token string">'cldr-dates-full/main/en/timeZoneNames.json'</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> deNumbers <span class="token keyword">from</span> <span class="token string">'cldr-numbers-full/main/de/numbers.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> deCurrencies <span class="token keyword">from</span> <span class="token string">'cldr-numbers-full/main/de/currencies.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> deCaGregorian <span class="token keyword">from</span> <span class="token string">'cldr-dates-full/main/de/ca-gregorian.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> deTimeZoneNames <span class="token keyword">from</span> <span class="token string">'cldr-dates-full/main/de/timeZoneNames.json'</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> esNumbers <span class="token keyword">from</span> <span class="token string">'cldr-numbers-full/main/es/numbers.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> esCurrencies <span class="token keyword">from</span> <span class="token string">'cldr-numbers-full/main/es/currencies.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> esCaGregorian <span class="token keyword">from</span> <span class="token string">'cldr-dates-full/main/es/ca-gregorian.json'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> esTimeZoneNames <span class="token keyword">from</span> <span class="token string">'cldr-dates-full/main/es/timeZoneNames.json'</span><span class="token punctuation">;</span>

<span class="token comment">// Load all CLDR data</span>
<span class="token function">load</span><span class="token punctuation">(</span>
  likelySubtags<span class="token punctuation">,</span>
  currencyData<span class="token punctuation">,</span>
  weekData<span class="token punctuation">,</span>
  enNumbers<span class="token punctuation">,</span>
  enCurrencies<span class="token punctuation">,</span>
  enCaGregorian<span class="token punctuation">,</span>
  enTimeZoneNames<span class="token punctuation">,</span>
  deNumbers<span class="token punctuation">,</span>
  deCurrencies<span class="token punctuation">,</span>
  deCaGregorian<span class="token punctuation">,</span>
  deTimeZoneNames<span class="token punctuation">,</span>
  esNumbers<span class="token punctuation">,</span>
  esCurrencies<span class="token punctuation">,</span>
  esCaGregorian<span class="token punctuation">,</span>
  esTimeZoneNames
<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">DataDisplay</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> intl <span class="token operator">=</span> <span class="token function">useInternationalization</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> orderDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token number">2024</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">15</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// March 15, 2024</span>
  <span class="token keyword">const</span> orderTotal <span class="token operator">=</span> <span class="token number">1234.56</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> taxRate <span class="token operator">=</span> <span class="token number">0.08</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>data-card<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h4</span><span class="token punctuation">&gt;</span></span>Order Summary<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h4</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>data-row<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>Order Date<span class="token punctuation">:</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>strong</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>intl<span class="token punctuation">.</span><span class="token function">formatDate</span><span class="token punctuation">(</span>orderDate<span class="token punctuation">,</span> <span class="token string">'d'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>data-row<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>Subtotal<span class="token punctuation">:</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>strong</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>intl<span class="token punctuation">.</span><span class="token function">formatNumber</span><span class="token punctuation">(</span>orderTotal<span class="token punctuation">,</span> <span class="token string">'c'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>data-row<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>Tax Rate<span class="token punctuation">:</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>strong</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>intl<span class="token punctuation">.</span><span class="token function">formatNumber</span><span class="token punctuation">(</span>taxRate<span class="token punctuation">,</span> <span class="token string">'p0'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>data-row<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>Tax Amount<span class="token punctuation">:</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>strong</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>intl<span class="token punctuation">.</span><span class="token function">formatNumber</span><span class="token punctuation">(</span>orderTotal <span class="token operator">*</span> taxRate<span class="token punctuation">,</span> <span class="token string">'c'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>data-row total<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>Total<span class="token punctuation">:</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>strong</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>intl<span class="token punctuation">.</span><span class="token function">formatNumber</span><span class="token punctuation">(</span>orderTotal <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">+</span> taxRate<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'c'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">App</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>locale<span class="token punctuation">,</span> setLocale<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">'en'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> <span class="token function-variable function">handleLocaleChange</span> <span class="token operator">=</span> <span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">setLocale</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> localeOptions <span class="token operator">=</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span> text<span class="token punctuation">:</span> <span class="token string">'English (US)'</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token string">'en'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> text<span class="token punctuation">:</span> <span class="token string">'Deutsch (Deutschland)'</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token string">'de'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> text<span class="token punctuation">:</span> <span class="token string">'Espa&ntilde;ol (Espa&ntilde;a)'</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token string">'es'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>locale-selector<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Select Locale<span class="token punctuation">:</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>DropDownList</span>
          <span class="token attr-name">data</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>localeOptions<span class="token punctuation">}</span></span>
          <span class="token attr-name">textField</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span>
          <span class="token attr-name">dataItemKey</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>value<span class="token punctuation">"</span></span>
          <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>localeOptions<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">(</span>l<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> l<span class="token punctuation">.</span>value <span class="token operator">===</span> locale<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
          <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleLocaleChange<span class="token punctuation">}</span></span>
        <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>IntlProvider</span> <span class="token attr-name">locale</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>locale<span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>DataDisplay</span> <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>IntlProvider</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span>
</code></pre><p>In the above example, we&rsquo;ve created an order summary that displays dates, currency values and percentages. When the user selects a different locale from the dropdown, all values automatically update to match the formatting conventions of that locale. The date format changes, decimal separators adjust, currency symbols update and percentage displays follow local conventions&mdash;all without any manual formatting logic.</p><p><img src="https://www.telerik.com/sfimages/default-source/blogs/2025/2025-12//kendoreact-internationalization-interactive.gif" alt="" /></p><h2 id="wrap-up">Wrap-up</h2><p>The KendoReact Internationalization package provides an effective way to format dates and numbers according to cultural conventions. By leveraging <a target="_blank" href="https://cldr.unicode.org/">CLDR data</a> and the <code>IntlProvider</code> component, we can enable our React applications to display data in formats that feel natural to users, regardless of their location.</p><p>For more details on the KendoReact Internationalization package, including more advanced formatting options and parsing capabilities, check out the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/intl">official documentation</a>.</p><p>Try the library for yourself:</p><p><a target="_blank" href="https://www.telerik.com/try/kendo-react-ui" class="Btn">Try KendoReact</a></p><img src="https://feeds.telerik.com/link/23056/17251907.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:2088b2d1-76ec-4de8-a350-6a48c23bfd16</id>
    <title type="text">Building ChatGPT Apps with React Components: Introducing KendoReact + Apps SDK</title>
    <summary type="text">Our new KendoReact + ChatGPT repo makes it easier to build Apps SDK experiences using KendoReact Free, a collection of free enterprise-grade components for React.</summary>
    <published>2026-01-08T19:41:59Z</published>
    <updated>2026-04-23T22:50:00Z</updated>
    <author>
      <name>Kathryn Grayson Nanz </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23056/17249592/building-chatgpt-apps-react-components-introducing-kendoreact-apps-sdk"/>
    <content type="text"><![CDATA[<p><span class="featured">Our new KendoReact + ChatGPT repo makes it easier to build Apps SDK experiences using KendoReact Free, a collection of free enterprise-grade components for React.</span></p><p>The <a href="https://developers.openai.com/apps-sdk/" target="_blank">OpenAI Apps SDK</a> opens the door to a new category of applications: chat-native apps that combine conversation, data and UI into a single interface. But for many React developers, figuring out exactly how to get UI components to show up and behave correctly inside the Apps SDK model is a hurdle that can be difficult to jump.</p><p>If that sounds like you, then good news! Our new <a target="_blank" href="https://github.com/telerik/openai-apps-sdk-kendo-examples?tab=readme-ov-file">KendoReact + ChatGPT repo</a> makes it easier to build Apps SDK experiences using Progress KendoReact Free, a collection of free enterprise-grade components for React. </p><p>This repo exists to help remove some of that guesswork. It includes working examples using <a target="_blank" href="https://www.telerik.com/kendo-react-ui/free-react-components">KendoReact Free</a> components, so you can understand exactly how to implement them in this new context. It also includes a Node.js server setup and end-to-end patterns that you can adapt for your own Apps SDK projects.</p><h2>For Example?</h2><p>For example, one of the most challenging aspects of working with the Apps SDK is the narrow view size: the chat view space is only 768px wide. That means that any UI components a developer wants to use must already be completely responsive or adaptive, or it won&rsquo;t work well in the limited space available. </p><p>By using the KendoReact components, this is already handled! Our components have been highly responsive for years, built to work just as well on mobile as on desktop&mdash;making them a perfect match for the smaller view of the chat UI. Similarly, our components already have inbuilt interactivity with the view, meaning that clients won&rsquo;t need to do the same level of extensive prompting and testing they would with other components.</p><p>We designed this as a practical starting point: a place to see what our optimized, functional components look like in a real Apps SDK context, so you can fork the examples and use them to launch your own projects.</p><h2>Why This Matters to You</h2><p>The Apps SDK introduces a new way to build software: chat-native applications where UI elements are rendered as part of a conversational interface. KendoReact Free gives you a collection of our most popular and beloved UI components, and this repo shows how to bring them into that new environment with minimal friction. </p><p>That means that all the things you get with KendoReact Free are now available for your ChatGPT apps, including:</p><ul><li>50 extensively tested and enterprise-quality components</li><li>A professional design system created by our dedicated team</li><li>Four design themes that align with popular existing third-party design systems (Material, Fluent, Bootstrap and Kendo)</li><li>Responsive and mobile interactivity&mdash;perfect for ChatGPT&rsquo;s narrow conversation-oriented view</li><li>Easy template extensibility</li><li>A library of components that are screen-reader friendly, WCAG and Section 508 compliant, and human-tested for accessibility</li></ul><p>If you&rsquo;re experimenting with the Apps SDK, building internal tools or prototyping a new chat-first workflow, this project gives you a faster way to get hands-on.</p><h2>Try It Out!</h2><p>To get started, just clone <a target="_blank" href="https://github.com/telerik/openai-apps-sdk-kendo-examples?tab=readme-ov-file">the repo</a>, follow the setup instructions, explore the examples and adapt from there. Everything is MIT-licensed and open to use and extend.</p><p>If you have feedback, questions or ideas, open an issue or start a discussion in the repo. We look forward to seeing what you build!</p><img src="https://feeds.telerik.com/link/23056/17249592.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:474def98-435d-4ab8-8bb0-94f20b4b6c94</id>
    <title type="text">React Basics: Thinking in React</title>
    <summary type="text">To be an effective React developer, you need to learn how to think in React, to structure your app UI component hierarchy so that the state flows in one direction.</summary>
    <published>2026-01-05T14:42:07Z</published>
    <updated>2026-04-23T22:50:00Z</updated>
    <author>
      <name>David Adeneye Abiodun </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23056/17247213/react-basics-thinking-react"/>
    <content type="text"><![CDATA[<p><span class="featured">To be an effective React developer, you need to learn how to think in React, to structure your app UI component hierarchy so that the state flows in one direction.</span></p><p>When you&rsquo;re new to React, it&rsquo;s easy to focus on JSX, hooks, props and state. But what really unlocks the power of React isn&rsquo;t memorizing APIs. It&rsquo;s learning how to think in React.</p><p>Once you understand React&rsquo;s mental model, UI development stops feeling like a tangle of jQuery patches or DOM manipulations and instead feels like snapping together Lego pieces.</p><p>This guide walks you through how to think in React, step by step, so you can build interfaces that are clean, scalable and easy to reason about.</p><h2 id="why-‘thinking-in-react’-is-a-big-deal">Why &lsquo;Thinking in React&rsquo; Is a Big Deal</h2><p>If you&rsquo;re coming from an HTML/CSS or jQuery background, you&rsquo;re probably used to working with static templates and manually tweaking the DOM to make things interactive. React changes that completely.</p><p>In React, the UI is a direct reflection of your state. Instead of imperatively telling the DOM what to do, you simply describe how the UI should look based on the current state&mdash;and React takes care of keeping everything in sync. To make the most of this, you have to shift your mindset from &ldquo;pages and DOM updates&rdquo; to &ldquo;components and state-driven UI.&rdquo;</p><p>When building a user interface application, you&rsquo;ll usually start with two things: a mockup from the designer and some data from the backend API. For this guide, we&rsquo;ll use a simple todo app as our example.</p><p>Our todo application UI/Mockup will look like this:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-11/mockup-for-todo-app.png?sfvrsn=4da22ec7_2" title="Mockup for Todo App" alt="Todo UI Mock" /></p><p>And here&rsquo;s the link to the source code: <a target="_blank" href="https://codesandbox.io/p/sandbox/todo-app-in-react-zqpth8">https://codesandbox.io/p/sandbox/todo-app-in-react-zqpth8</a>.</p><p>And here&rsquo;s the kind of JSON response we&rsquo;d expect from an API (for now, we&rsquo;ll hardcode it since we don&rsquo;t have a real backend):</p><pre class=" language-json"><code class="prism  language-json"><span class="token punctuation">[</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> title<span class="token punctuation">:</span> <span class="token string">"Write React Article"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> title<span class="token punctuation">:</span> <span class="token string">"Edit React Articles"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> title<span class="token punctuation">:</span> <span class="token string">"Submit React Articles"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span>
</code></pre><p>According to the React documentation, to implement a UI in React, you typically follow five steps. We will utilize these techniques throughout the process of thinking through how to build the todo application.</p><h2 id="step-1-break-the-ui-into-a-component-hierarchy">Step 1: Break the UI into a Component Hierarchy</h2><p>When you&rsquo;re preparing to build a UI in React, the best starting point is a clear design. This may come from your product designer (using Figma, Sketch, <a href="https://www.telerik.com/themebuilder" target="_blank">Progress ThemeBuilder</a> or similar), or you might create it yourself as a UX engineer. Either way, your primary task is to decompose that design into logical, reusable components.</p><p>Let&rsquo;s take our todo application as an example. The simplest way to begin is by outlining each component and subcomponent in the mockup and clearly labeling them. Many design tools streamline this by enabling designers to name layers or components directly in the file.</p><p>As you break down the design, keep these perspectives in mind:</p><ul><li><strong>Programming perspective:</strong> Think in terms of the single responsibility principle. A component should ideally do one thing well. If it starts growing beyond that, break it into smaller subcomponents.</li><li><strong>CSS perspective:</strong> Imagine what you&rsquo;d normally assign a class selector to. Components often map to those same chunks of UI, though not always as granular.</li><li><strong>Design perspective:</strong> Examine how layers are grouped and organized within the design file. That structure often hints at where components should be split.</li></ul><p>In many cases, the structure of your backend data will also influence your component breakdown. Well-structured APIs often map neatly onto the UI&mdash;both follow the same information architecture. Break your UI into components so that each one corresponds to a specific part of your data model.</p><p>For our todo application, here&rsquo;s a breakdown of six main components:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-11/todo-app-components.png?sfvrsn=7abcd6a4_2" title="Todo App Components breakdown" alt="Todo App Components" /></p><ol><li><code>TodoApplicationTable</code> (yellow): Wraps the entire app.</li><li><code>TodoFormSection</code> (green): Handles user input for adding todos.</li><li><code>TodosTable</code> (blue): Displays the list of todos along with related actions.</li><li><code>TodosCountSection</code> (orange): Shows the total number of todos.</li><li><code>TodoItem</code> (purple): Represents each individual todo and its actions.</li><li><code>FilterTodosTable</code> (red): Provides controls for filtering the todo list.</li></ol><p>One thing to note: Inside <code>TodosTable</code> (blue), the <code>TodoCountSection</code> isn&rsquo;t broken out as a separate component. That&rsquo;s a design choice. It works fine to keep it in line for now, but if the header grows more complex later, you&rsquo;ll likely want to extract it into its own <code>TodosTableHeader</code> component.</p><p>Once you&rsquo;ve identified the pieces, the next step is to arrange them into a hierarchy. Components that appear inside others in the mockup should be children in your component tree. For our app, that looks like this:</p><pre><code>TodoApplicationTable
  ├── TodoFormSection
  └── TodosTable
       ├── TodoCountSection
       ├── TodoItem
  └── FilterTodosTable
</code></pre><p>And that&rsquo;s it for Step 1. You&rsquo;ve successfully mapped your design into a clear component hierarchy.</p><h2 id="step-2-build-a-static-version-in-react">Step 2: Build a Static Version in React</h2><p>With your component hierarchy mapped out, the next step is to start coding. Before adding any interactivity, it&rsquo;s best to build a static version of the UI&mdash;one that renders the correct structure and data but doesn&rsquo;t handle any changes yet.</p><p>This step keeps things simple. Writing the static version is mostly about composition: putting components together and passing data down through <code>props</code>. Interactivity and state management come later, since those usually involve more thinking than typing.</p><p>At this stage, avoid using the state entirely. <strong>State is for dynamic, changing data.</strong> Since we&rsquo;re only building the static skeleton, <code>props</code> are all you need. Parent components pass data to children, keeping your UI predictable and consistent.</p><p>You can approach this in two ways:</p><ul><li><strong>Top-down:</strong> Start with higher-level components such as <code>TodoApplicationTable</code> and work your way down.</li><li><strong>Bottom-up:</strong> Start small with leaf components such as <code>FilterTodoTable</code> and build upward.</li></ul><p>For simple apps, top-down usually feels faster. For bigger projects, a bottom-up approach often helps keep things organized.</p><p>Here&rsquo;s a static version of our todo application:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">import</span> <span class="token string">"./styles.css"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> initialTodos <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> title<span class="token punctuation">:</span> <span class="token string">"Write React Article"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> title<span class="token punctuation">:</span> <span class="token string">"Edit React Articles"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> title<span class="token punctuation">:</span> <span class="token string">"Submit React Articles"</span><span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>div className<span class="token operator">=</span><span class="token string">"todoapp stack-large"</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>h1 className<span class="token operator">=</span><span class="token string">"header"</span><span class="token operator">&gt;</span>Todo App<span class="token operator">&lt;</span><span class="token operator">/</span>h1<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>TodoForm <span class="token operator">/</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>TodoList todos<span class="token operator">=</span><span class="token punctuation">{</span>initialTodos<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>FilterTodo <span class="token operator">/</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span>


<span class="token keyword">function</span> <span class="token function">TodoForm</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>form<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>input
        type<span class="token operator">=</span><span class="token string">"text"</span>
        id<span class="token operator">=</span><span class="token string">"new-todo-input"</span>
        placeholder<span class="token operator">=</span><span class="token string">"What needs to be done?"</span>
        className<span class="token operator">=</span><span class="token string">"input input__lg"</span>
        name<span class="token operator">=</span><span class="token string">"text"</span>
        autoComplete<span class="token operator">=</span><span class="token string">"off"</span>
      <span class="token operator">/</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>button type<span class="token operator">=</span><span class="token string">"submit"</span> className<span class="token operator">=</span><span class="token string">"btn btn__primary btn__lg"</span><span class="token operator">&gt;</span>
        Add
      <span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>form<span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>


<span class="token keyword">function</span> <span class="token function">TodoList</span><span class="token punctuation">(</span><span class="token punctuation">{</span> todos <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>h2 id<span class="token operator">=</span><span class="token string">"list-heading"</span><span class="token operator">&gt;</span><span class="token punctuation">{</span>todos<span class="token punctuation">.</span>length<span class="token punctuation">}</span> tasks remaining<span class="token operator">&lt;</span><span class="token operator">/</span>h2<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>ul role<span class="token operator">=</span><span class="token string">"list"</span> className<span class="token operator">=</span><span class="token string">"todo-list stack-large todo-exception"</span><span class="token operator">&gt;</span>
        <span class="token punctuation">{</span>todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span>
          <span class="token operator">&lt;</span>li key<span class="token operator">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span> className<span class="token operator">=</span><span class="token string">"todo stack-small"</span><span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>div className<span class="token operator">=</span><span class="token string">"todo-cb"</span><span class="token operator">&gt;</span>
              <span class="token operator">&lt;</span>input id<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token string">`todo-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>todo<span class="token punctuation">.</span>id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">}</span> type<span class="token operator">=</span><span class="token string">"checkbox"</span> defaultChecked<span class="token operator">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>done<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
              <span class="token operator">&lt;</span>label className<span class="token operator">=</span><span class="token string">"todo-label"</span> htmlFor<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token string">`todo-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>todo<span class="token punctuation">.</span>id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
                <span class="token punctuation">{</span>todo<span class="token punctuation">.</span>title<span class="token punctuation">}</span>
              <span class="token operator">&lt;</span><span class="token operator">/</span>label<span class="token operator">&gt;</span>
              <span class="token operator">&lt;</span>button type<span class="token operator">=</span><span class="token string">"button"</span> className<span class="token operator">=</span><span class="token string">"btn"</span><span class="token operator">&gt;</span>
                Edit <span class="token operator">&lt;</span>span className<span class="token operator">=</span><span class="token string">"visually-hidden"</span><span class="token operator">&gt;</span>Edit<span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">&gt;</span>
              <span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">&gt;</span>
              <span class="token operator">&lt;</span>button type<span class="token operator">=</span><span class="token string">"button"</span> className<span class="token operator">=</span><span class="token string">"btn btn__danger"</span><span class="token operator">&gt;</span>
                Delete <span class="token operator">&lt;</span>span className<span class="token operator">=</span><span class="token string">"visually-hidden"</span><span class="token operator">&gt;</span>Delete<span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">&gt;</span>
              <span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
          <span class="token operator">&lt;</span><span class="token operator">/</span>li<span class="token operator">&gt;</span>
        <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>ul<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>


<span class="token keyword">function</span> <span class="token function">FilterTodo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>div className<span class="token operator">=</span><span class="token string">"filters btn-group todo-exception"</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>button type<span class="token operator">=</span><span class="token string">"button"</span> className<span class="token operator">=</span><span class="token string">"btn toggle-btn"</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>span<span class="token operator">&gt;</span>All<span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>button type<span class="token operator">=</span><span class="token string">"button"</span> className<span class="token operator">=</span><span class="token string">"btn toggle-btn"</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>span<span class="token operator">&gt;</span>Active<span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>button type<span class="token operator">=</span><span class="token string">"button"</span> className<span class="token operator">=</span><span class="token string">"btn toggle-btn"</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>span<span class="token operator">&gt;</span>Completed<span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>At this point, each component is reusable and renders part of the data model. Notice how <code>TodoList</code> receives the list of todos as a <code>prop</code> and passes it down the tree. This is React&rsquo;s <strong>one-way data flow</strong> in action: data always moves from parent to child, top to bottom.</p><p>No state yet&mdash;that comes in the next step when we make the app interactive.</p><h2 id="step-3-identify-the-minimal-but-complete-representation-of-ui-state">Step 3: Identify the Minimal (but Complete) Representation of UI State</h2><p>Now comes the key question: what actually changes in this UI?</p><p>To make your app interactive, you need to let users update the underlying data model. That&rsquo;s where the state comes in. State is the minimal set of data your app needs to remember over time. The golden rule: keep your state <a target="_blank" href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY (Don&rsquo;t Repeat Yourself)</a>. Store only what&rsquo;s essential and derive everything else from it when needed.</p><p>For example, in our todo app, you definitely need to store the list of todos as an array. But if you also want to display the total number of todos, you don&rsquo;t keep that number in state&mdash;you just calculate it from <code>todos.length</code>.</p><p>Now, let&rsquo;s apply this thinking to our todo application demo example. Here are the key pieces of data:</p><ul><li>The original list of todos</li><li>The input text entered by the user</li><li>The value of the checkbox</li><li>The filtered list of todos</li><li>The total number of todos</li><li>The value of the todo currently being edited</li></ul><p>Which of this should be state? To figure that out, apply three simple questions to each piece:</p><ol><li><strong>Does it change over time?</strong> If no, it&rsquo;s not state.</li><li><strong>Is it passed in from a parent via props?</strong> If yes, it&rsquo;s not state.</li><li><strong>Can it be derived from existing state or props?</strong> If yes, it&rsquo;s not state.</li></ol><p>What&rsquo;s left is probably state. Let&rsquo;s go through them one by one again:</p><ul><li><strong>The original list of todos</strong> &rarr; comes in via props, not state.</li><li><strong>The input text</strong> &rarr; changes over time, so yes, it&rsquo;s state.</li><li><strong>Checkbox value</strong> &rarr; can be derived from the todos array, not state.</li><li><strong>Filtered list of todos</strong> &rarr; depends on user actions and changes over time, so yes, it&rsquo;s state.</li><li><strong>The total number of todos</strong> &rarr; can be computed from <code>todos.length</code>, not state.</li><li><strong>The edited todo value</strong> &rarr; changes over time, so yes, it&rsquo;s state.</li></ul><p>That leaves us with three pieces of state. Everything else can (and should) be derived from these. Keeping your state minimal and explicit makes your app easier to reason about, debug and maintain.</p><h2 id="step-4-identify-where-your-state-should-live">Step 4: Identify Where Your State Should Live</h2><p>Once you&rsquo;ve identified the minimal pieces of state your app needs, the next step is figuring out which component should own that state. In React, data flows in one direction, from parent to child, so placing state in the right spot makes everything easier to manage.</p><p>If you&rsquo;re new to this, it might feel a bit tricky, but you can work it out by following this process:</p><ol><li>For each piece of state, list all the components that depend on it.</li><li>Find their closest common parent in the components tree.</li><li>Decides the closest common parent in the component tree:<br />a. Most of the time, you&rsquo;ll put it in that common parent.<br />b. Sometimes, it makes sense to lift the state even higher.<br />c. If no existing component feels right, create a new one just to hold the state and place it above the common parent.</li></ol><p>This helps to manage the state at the right level, so data can flow down as props to all components that need it.</p><p>In the previous steps, you will have noticed we have three pieces of state in the todo application: the added todo text, the value of the edited todo and the filtered todo list. In this example, the state of todos is what&rsquo;s common to every other component.</p><p>So, let&rsquo;s go through our strategy for them:</p><ol><li>Identify components that use state:</li></ol><ul><li><code>TodosTable</code> needs to list todos based on the state of (added todo text, checkbox value, editing and filtering options).</li><li><code>TodoFormSection</code> needs to get the state of the title of the todo that&rsquo;s been added.</li><li><code>FilterTodosTable</code> needs to display the state of the filtering.</li></ul><ol start="2"><li><p>Find their common parent: The first component both components share is the <code>TodoApplicationTable</code> which is the App component that housed all the components.</p></li><li><p>Decide where the state lives: We&rsquo;ll keep the states common state to all, which is the <code>todos</code> state and the <code>filtering</code> state, in the parent component. The new todo input state will be kept in the <code>TodoFormSection</code> component. In our code demo, we named the component <code>TodoForm.js</code>.</p></li></ol><p>Then add state to the component with the <a target="_blank" href="https://react.dev/reference/react/useState"><code>useState()</code> hook</a>. Hooks are a special function that enable you to &ldquo;hook into&rdquo; React. Add two state variables at the top of the <code>App</code> component which we can also refer to as <code>TodoApplicationTable</code>, and specify their initial state.</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>todos<span class="token punctuation">,</span> setTodos<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span>initialTodos<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token punctuation">[</span>filter<span class="token punctuation">,</span> setFilter<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">"All"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Remember, we&rsquo;re using the initial mock data first. So we set the <code>todos</code> state to that data before adding any user-created items to the list. For filtering, the default state is set to <code>All</code>, which is why we&rsquo;re using <code>All</code> as the initial value.</p><p>Then pass the <code>todos</code> as props to the <code>TodoList</code> components as a prop :</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TodoList</span> <span class="token attr-name">todos</span><span class="token attr-value"><span class="token punctuation">=</span>{todos}</span> <span class="token punctuation">/&gt;</span></span>
</code></pre><p>For the next state to add todo from user input, open the <code>TodoForm.js</code> component, which can also be referred to as the <code>TodoFormSection</code>, and add one state variable at the top of the component:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>title<span class="token punctuation">,</span> setTitle<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The next state is for editing the todo, also add one state variable at the top level of <code>Todo</code> components, which <code>TodoList</code> serves as a parent component too:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>isEditing<span class="token punctuation">,</span> setIsEditing<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>At this point, you haven&rsquo;t added any code to respond to user actions such as typing yet. This will be the final step.</p><h2 id="step-5-add-inverse-data-flow">Step 5: Add Inverse Data Flow</h2><p>Now it&rsquo;s time to wire up interactivity. At this point, our app renders correctly, and state flows down from parent to child. But React apps aren&rsquo;t just about displaying data&mdash;they need to respond to user input. This is where <strong>inverse data flow</strong> comes in.</p><p>React makes this process explicit, which means a little more typing compared to traditional two-way data binding. If you try typing in the input or toggling the checkbox in the example, nothing happens. That&rsquo;s intentional.</p><p>The goal is to update state whenever the user interacts with the form inputs. Since the todos state lives in the main parent component, only it can set the state of the todo. So for the <code>TodoForm</code> component to update the todos state whenever a user input a new todo, we need to pass the function that add the new todo to the lists of the todo to the <code>TodoFrom</code> components:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">TodoApp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>todos<span class="token punctuation">,</span> setTodos<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span>initialTodos<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">function</span> <span class="token function">handleAddTodo</span><span class="token punctuation">(</span>title<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">setTodos</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
      <span class="token operator">...</span>todos<span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        id<span class="token punctuation">:</span> nextId<span class="token operator">++</span><span class="token punctuation">,</span>
        title<span class="token punctuation">:</span> title<span class="token punctuation">,</span>
        done<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
&hellip;
<span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>div className<span class="token operator">=</span><span class="token string">"todoapp stack-large"</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>h1 className<span class="token operator">=</span><span class="token string">"header"</span><span class="token operator">&gt;</span>Todo App<span class="token operator">&lt;</span><span class="token operator">/</span>h1<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>TodoForm onAddTodo<span class="token operator">=</span><span class="token punctuation">{</span>handleAddTodo<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
      
     &hellip;<span class="token punctuation">.</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Then in your <code>TodoForm</code> add the the state and function to receive user input and call <code>onAddTodo</code> whenever user submits:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">function</span> <span class="token function">TodoForm</span><span class="token punctuation">(</span><span class="token punctuation">{</span> onAddTodo <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>title<span class="token punctuation">,</span> setTitle<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> <span class="token function-variable function">handleSubmit</span> <span class="token operator">=</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// prevent page refresh</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>title<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token comment">// optional: avoid empty todos</span>
    <span class="token function">onAddTodo</span><span class="token punctuation">(</span>title<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">setTitle</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>input
        type<span class="token operator">=</span><span class="token string">"text"</span>
        id<span class="token operator">=</span><span class="token string">"new-todo-input"</span>
        placeholder<span class="token operator">=</span><span class="token string">"What needs to be done?"</span>
        className<span class="token operator">=</span><span class="token string">"input input__lg"</span>
        name<span class="token operator">=</span><span class="token string">"text"</span>
        autoComplete<span class="token operator">=</span><span class="token string">"off"</span>
        value<span class="token operator">=</span><span class="token punctuation">{</span>title<span class="token punctuation">}</span>
        onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setTitle</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span>
      <span class="token operator">/</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>button type<span class="token operator">=</span><span class="token string">"submit"</span> className<span class="token operator">=</span><span class="token string">"btn btn__primary btn__lg"</span><span class="token operator">&gt;</span>
        Add
      <span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>form<span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>We follow the same pattern for editing and toggling: App owns the state, defines an updater and passes it down.</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">TodoApp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
   <span class="token comment">// &hellip;</span>
    <span class="token keyword">function</span> <span class="token function">handleChangeTodo</span><span class="token punctuation">(</span>nextTodo<span class="token punctuation">)</span> <span class="token punctuation">{</span>
       <span class="token function">setTodos</span><span class="token punctuation">(</span>
          todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>t<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token keyword">if</span> <span class="token punctuation">(</span>t<span class="token punctuation">.</span>id <span class="token operator">===</span> nextTodo<span class="token punctuation">.</span>id<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token keyword">return</span> nextTodo<span class="token punctuation">;</span>
     <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
          <span class="token keyword">return</span> t<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
     <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token keyword">function</span> <span class="token function">handleDeleteTodo</span><span class="token punctuation">(</span>todoId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
       <span class="token function">setTodos</span><span class="token punctuation">(</span>todos<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span>t<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> t<span class="token punctuation">.</span>id <span class="token operator">!==</span> todoId<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>TodoList
      todos<span class="token operator">=</span><span class="token punctuation">{</span>todos<span class="token punctuation">}</span>
      onChangeTodo<span class="token operator">=</span><span class="token punctuation">{</span>handleChangeTodo<span class="token punctuation">}</span>
      onDeleteTodo<span class="token operator">=</span><span class="token punctuation">{</span>handleDeleteTodo<span class="token punctuation">}</span>
    <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Inside <code>TodoItem</code>, we call these functions when the user edits text, toggles a checkbox or deletes a task.</p><p>Repeat this process for the other components, adding inverse data flow with state and interactivity as needed. If you&rsquo;re new to React, we&rsquo;ll walk you through building this todo application from scratch in blog post <a target="_blank" href="https://www.telerik.com" data-sf-ec-immutable="">React Basics: Interactivity and State</a>.</p><p>Here&rsquo;s the full code: <a target="_blank" href="https://codesandbox.io/p/sandbox/todo-app-in-react-zqpth8">https://codesandbox.io/p/sandbox/todo-app-in-react-zqpth8</a></p><p>Now the application is fully working:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-11/todo-app-demo.gif?sfvrsn=19691eb2_2" title="Demo of a Todo App" alt="Todo App Demo gif" /></p><h2 id="conclusion">Conclusion</h2><p>&ldquo;Thinking in React&rdquo; is less about coding and more about adopting a new way of seeing UIs. You&rsquo;re no longer shuffling DOM nodes by hand&mdash;you&rsquo;re structuring your app as a hierarchy of components, each powered by state flowing in one direction. Once you grasp that, scaling your application feels far less intimidating because every piece has its place.</p><p>In this walk-through, we use a todo app to put React&rsquo;s five-step process into practice: breaking down the UI, building a static version, identifying state, deciding where it belongs and implementing inverse data flow.</p><p>With this approach, you&rsquo;re not just writing React, you&rsquo;re <strong>thinking</strong> in React. And that mindset shift is what turns a beginner into a confident React developer.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Turn Prompts into Pages: Telerik Agentic UI Generator</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Accelerate enterprise UI delivery with orchestrated, <a target="_blank" href="https://www.telerik.com/blogs/turn-prompts-pages-telerik-agentic-ui-generator">prompt-driven tools</a>.</p></div></div></aside><img src="https://feeds.telerik.com/link/23056/17247213.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:e47158f1-f146-4ae8-a119-27f4911de84c</id>
    <title type="text">Caching with TanStack Query</title>
    <summary type="text">TanStack Query caching creates an instantaneous feeling user experience. Combined with the KendoReact Loader component, we have a polished React app handling even complex server state smoothly.</summary>
    <published>2025-12-30T13:41:26Z</published>
    <updated>2026-04-23T22:50:00Z</updated>
    <author>
      <name>Hassan Djirdeh </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23056/17243869/caching-tanstack-query"/>
    <content type="text"><![CDATA[<p><span class="featured">TanStack Query caching creates an instantaneous feeling user experience. Combined with the KendoReact Loader component, we have a polished React app handling even complex server state smoothly.</span></p><p>Data fetching in large-scale React applications often becomes a complex juggling act. We need to manage loading states, handle errors, prevent duplicate requests and figure out when our cached data becomes outdated. Without a proper strategy, we end up with components full of <a target="_blank" href="https://react.dev/reference/react/useEffect">useEffect</a> hooks and users waiting for the same data to load repeatedly.</p><p><a target="_blank" href="https://tanstack.com/query">TanStack Query</a> (formerly React Query) solves these problems by treating <strong>server state as a first-class citizen</strong> in React applications. Its intelligent caching system is the secret sauce that makes data fetching feel effortless while delivering a snappy user experience.</p><p>In this article, we&rsquo;ll explore how TanStack Query&rsquo;s caching works and demonstrate it with practical examples using the Progress <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/indicators/loader">KendoReact Loader component</a>.</p><blockquote><p>The KendoReact Loader component is part of the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/free-react-components">KendoReact Free</a> suite, which means you can use it in your projects without any license or registration requirements.</p></blockquote><h2 id="tanstack-query">TanStack Query</h2><p>TanStack Query is a library for fetching, caching and updating asynchronous data in React without touching any global state. It treats server state as a separate concern from client state (like UI toggles or form inputs).</p><p>With TanStack Query, we don&rsquo;t need to manage loading states or cache data ourselves manually. The library handles this for us by providing us a set of simple hooks that deliver data, loading status and error information directly to our components.</p><p>Let&rsquo;s start by installing the necessary packages:</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">npm</span> <span class="token function">install</span> @tanstack/react-query @progress/kendo-react-indicators
</code></pre><p>Every TanStack Query application needs a <code>QueryClient</code> and a <code>QueryClientProvider</code> to manage the cache and provide it to our component tree:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> QueryClient<span class="token punctuation">,</span> QueryClientProvider <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@tanstack/react-query'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> ProfileDemo <span class="token keyword">from</span> <span class="token string">'./ProfileDemo'</span><span class="token punctuation">;</span>

<span class="token comment">// Create a client</span>
<span class="token keyword">const</span> queryClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">QueryClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token comment">// Provide the client to our App</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>QueryClientProvider</span> <span class="token attr-name">client</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>queryClient<span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ProfileDemo</span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>QueryClientProvider</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span>
</code></pre><p>This setup creates the foundation for all our caching magic. The <code>QueryClient</code> manages the cache, while the <code>QueryClientProvider</code> makes it available to all child components.</p><h2 id="basic-caching-in-action">Basic Caching in Action</h2><p>Let&rsquo;s see TanStack Query&rsquo;s caching in action with a simple <code>&lt;UserProfile /&gt;</code> component. We&rsquo;ll fetch user data from the <a target="_blank" href="https://jsonplaceholder.typicode.com/">JSONPlaceholder API</a> and use the KendoReact Loader to show loading states.</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useQuery <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@tanstack/react-query'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Loader <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-indicators'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Button <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-buttons'</span><span class="token punctuation">;</span>

<span class="token comment">// Our data fetching function</span>
<span class="token keyword">const</span> fetchUser <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span>userId<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`https://jsonplaceholder.typicode.com/users/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>userId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>response<span class="token punctuation">.</span>ok<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'Failed to fetch user'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">UserProfile</span><span class="token punctuation">(</span><span class="token punctuation">{</span> userId <span class="token operator">=</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Queries</span>
  <span class="token keyword">const</span> query <span class="token operator">=</span> <span class="token function">useQuery</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    queryKey<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'user'</span><span class="token punctuation">,</span> userId<span class="token punctuation">]</span><span class="token punctuation">,</span>
    queryFn<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fetchUser</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>query<span class="token punctuation">.</span>isLoading<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loading-container<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Loader</span> <span class="token attr-name">size</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>large<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>infinite-spinner<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Loading user profile<span class="token operator">...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>query<span class="token punctuation">.</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>error<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Error<span class="token punctuation">:</span> <span class="token punctuation">{</span>query<span class="token punctuation">.</span>error<span class="token punctuation">.</span>message<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>user-profile<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">{</span>query<span class="token punctuation">.</span>isFetching <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>background-loading<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Loader</span> <span class="token attr-name">size</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>small<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>pulsing<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>Updating<span class="token operator">...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">)</span><span class="token punctuation">}</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>query<span class="token punctuation">.</span>data<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Email<span class="token punctuation">:</span> <span class="token punctuation">{</span>query<span class="token punctuation">.</span>data<span class="token punctuation">.</span>email<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Website<span class="token punctuation">:</span> <span class="token punctuation">{</span>query<span class="token punctuation">.</span>data<span class="token punctuation">.</span>website<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Company<span class="token punctuation">:</span> <span class="token punctuation">{</span>query<span class="token punctuation">.</span>data<span class="token punctuation">.</span>company<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">ProfileDemo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>showProfile<span class="token punctuation">,</span> setShowProfile<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>app<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setShowProfile</span><span class="token punctuation">(</span><span class="token operator">!</span>showProfile<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token punctuation">{</span>showProfile <span class="token operator">?</span> <span class="token string">'Hide'</span> <span class="token punctuation">:</span> <span class="token string">'Show'</span><span class="token punctuation">}</span> Profile
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Button</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">{</span>showProfile <span class="token operator">&amp;&amp;</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>UserProfile</span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">}</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Here&rsquo;s what happens when we run the above code:</p><ol><li><strong>First load</strong>: The <code>isLoading</code> state is <code>true</code>, so we see the large spinner while data is being fetched.</li><li><strong>Data arrives</strong>: The user profile displays, and <code>isLoading</code> becomes <code>false</code>.</li><li><strong>Toggle away and back</strong>: Click &ldquo;Hide Profile&rdquo; then &ldquo;Show Profile&rdquo; again. Notice the profile appears <strong>instantly</strong>! No loading spinner this time.</li><li><strong>Background update</strong>: We might see a small &ldquo;Updating&hellip;&rdquo; indicator because <code>query.isFetching</code> becomes <code>true</code> as TanStack Query <a target="_blank" href="https://tanstack.com/query/latest/docs/framework/react/guides/background-fetching-indicators">refetches in the background</a>.</li></ol><p>This is the magic of caching. The second time the component mounts, TanStack Query serves the cached data immediately while quietly updating it in the background!</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-09/tanstack-query-basic-caching.gif?sfvrsn=a8e89a84_2" alt="" /></p><h2 id="understanding-cache-keys">Understanding Cache Keys</h2><p>The <a target="_blank" href="https://tanstack.com/query/latest/docs/framework/react/guides/query-keys">queryKey</a> is crucial to how caching works. It&rsquo;s a unique identifier for our queries, and TanStack Query uses it to store and retrieve cached data.</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token comment">// These queries share the same cache</span>
<span class="token function">useQuery</span><span class="token punctuation">(</span><span class="token punctuation">{</span> queryKey<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'user'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> queryFn<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fetchUser</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">useQuery</span><span class="token punctuation">(</span><span class="token punctuation">{</span> queryKey<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'user'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> queryFn<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fetchUser</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// This query has its own cache</span>
<span class="token function">useQuery</span><span class="token punctuation">(</span><span class="token punctuation">{</span> queryKey<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'user'</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> queryFn<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fetchUser</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Query keys can be simple strings or arrays with multiple values. Using arrays allows us to create hierarchical keys that make cache invalidation more powerful:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token comment">// Cache different user data separately</span>
<span class="token punctuation">[</span><span class="token string">'user'</span><span class="token punctuation">,</span> userId<span class="token punctuation">]</span>
<span class="token punctuation">[</span><span class="token string">'user'</span><span class="token punctuation">,</span> userId<span class="token punctuation">,</span> <span class="token string">'posts'</span><span class="token punctuation">]</span>
<span class="token punctuation">[</span><span class="token string">'user'</span><span class="token punctuation">,</span> userId<span class="token punctuation">,</span> <span class="token string">'profile'</span><span class="token punctuation">]</span>
</code></pre><h2 id="configuring-cache-behavior">Configuring Cache Behavior</h2><p>TanStack Query&rsquo;s default caching behavior is designed to be <a target="_blank" href="https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults">aggressive but sensible</a>. However, we can fine-tune it based on our application&rsquo;s needs using two key options: <code>staleTime</code> and <code>gcTime</code>.</p><h3 id="understanding-staletime">Understanding staleTime</h3><p>By default, <code>staleTime</code> is <code>0</code>, meaning data is considered &ldquo;stale&rdquo; immediately after it&rsquo;s fetched. Stale data triggers background refetches when:</p><ul><li>The component remounts</li><li>The window regains focus</li><li>The network reconnects</li></ul><p>Let&rsquo;s modify our existing <code>UserProfile</code> component to see how <code>staleTime</code> affects behavior:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">function</span> <span class="token function">UserProfile</span><span class="token punctuation">(</span><span class="token punctuation">{</span> userId <span class="token operator">=</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Queries with 2-minute staleTime</span>
  <span class="token keyword">const</span> query <span class="token operator">=</span> <span class="token function">useQuery</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    queryKey<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'user'</span><span class="token punctuation">,</span> userId<span class="token punctuation">]</span><span class="token punctuation">,</span>
    queryFn<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fetchUser</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">,</span>
    staleTime<span class="token punctuation">:</span> <span class="token number">2</span> <span class="token operator">*</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">,</span> <span class="token comment">// 2 minutes</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>query<span class="token punctuation">.</span>isLoading<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loading-container<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Loader</span> <span class="token attr-name">size</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>large<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>infinite-spinner<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Loading user profile<span class="token operator">...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>query<span class="token punctuation">.</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>error<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Error<span class="token punctuation">:</span> <span class="token punctuation">{</span>query<span class="token punctuation">.</span>error<span class="token punctuation">.</span>message<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>user-profile<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">{</span>query<span class="token punctuation">.</span>isFetching <span class="token operator">?</span> <span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>background-loading<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Loader</span> <span class="token attr-name">size</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>small<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>pulsing<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>Updating<span class="token operator">...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>fresh-indicator<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>✨ Data is fresh<span class="token operator">!</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">)</span><span class="token punctuation">}</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>query<span class="token punctuation">.</span>data<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Email<span class="token punctuation">:</span> <span class="token punctuation">{</span>query<span class="token punctuation">.</span>data<span class="token punctuation">.</span>email<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Website<span class="token punctuation">:</span> <span class="token punctuation">{</span>query<span class="token punctuation">.</span>data<span class="token punctuation">.</span>website<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Company<span class="token punctuation">:</span> <span class="token punctuation">{</span>query<span class="token punctuation">.</span>data<span class="token punctuation">.</span>company<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Above, we&rsquo;ve specified 2 minutes as the new stale time value. With a 2-minute <code>staleTime</code>:</p><ul><li>Data appears instantly from cache when remounting.</li><li><strong>No background refetch</strong> happens during those 2 minutes.</li><li>The &ldquo;✨ Data is fresh!&rdquo; indicator shows when no refetching is occurring.</li><li>After 2 minutes, background refetching resumes.</li></ul><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-09/tanstack-query-staletime.gif?sfvrsn=982b3da2_2" alt="" /></p><h3 id="understanding-gctime-garbage-collection-time">Understanding gcTime (Garbage Collection Time)</h3><p>The <code>gcTime</code> (formerly <code>cacheTime</code>) determines how long inactive cached data stays in memory. The default is 5 minutes.</p><p>To see this in action with our <code>ProfileDemo</code>, we can modify the <code>UserProfile</code> component to use a shorter <code>gcTime</code>:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">function</span> <span class="token function">UserProfile</span><span class="token punctuation">(</span><span class="token punctuation">{</span> userId <span class="token operator">=</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Queries with short garbage collection time</span>
  <span class="token keyword">const</span> query <span class="token operator">=</span> <span class="token function">useQuery</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    queryKey<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'user'</span><span class="token punctuation">,</span> userId<span class="token punctuation">]</span><span class="token punctuation">,</span>
    queryFn<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fetchUser</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">,</span>
    gcTime<span class="token punctuation">:</span> <span class="token number">30</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">,</span> <span class="token comment">// 30 seconds</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>query<span class="token punctuation">.</span>isLoading<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loading-container<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Loader</span> <span class="token attr-name">size</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>large<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>infinite-spinner<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Loading user profile<span class="token operator">...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>query<span class="token punctuation">.</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>error<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Error<span class="token punctuation">:</span> <span class="token punctuation">{</span>query<span class="token punctuation">.</span>error<span class="token punctuation">.</span>message<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>user-profile<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>query<span class="token punctuation">.</span>data<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Email<span class="token punctuation">:</span> <span class="token punctuation">{</span>query<span class="token punctuation">.</span>data<span class="token punctuation">.</span>email<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Website<span class="token punctuation">:</span> <span class="token punctuation">{</span>query<span class="token punctuation">.</span>data<span class="token punctuation">.</span>website<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Company<span class="token punctuation">:</span> <span class="token punctuation">{</span>query<span class="token punctuation">.</span>data<span class="token punctuation">.</span>company<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>With a 30-second <code>gcTime</code>, if we use the &ldquo;Hide Profile&rdquo; button in our <code>ProfileDemo</code> and wait more than 30 seconds before clicking &ldquo;Show Profile&rdquo; again, we&rsquo;ll see the loading spinner because the cache was garbage collected.</p><h2 id="comparing-caching-scenarios">Comparing Caching Scenarios</h2><p>Let&rsquo;s enhance our <code>ProfileDemo</code> to create a comparison of different caching strategies:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useQuery <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@tanstack/react-query'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Loader <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-indicators'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Button <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-buttons'</span><span class="token punctuation">;</span>

<span class="token comment">// Enhanced UserProfile component that accepts cache configuration</span>
<span class="token keyword">function</span> <span class="token function">UserProfile</span><span class="token punctuation">(</span><span class="token punctuation">{</span> userId <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">,</span> title <span class="token operator">=</span> <span class="token string">"User Profile"</span><span class="token punctuation">,</span> cacheConfig <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> query <span class="token operator">=</span> <span class="token function">useQuery</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    queryKey<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'user'</span><span class="token punctuation">,</span> userId<span class="token punctuation">,</span> title<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// Include title to make each query unique</span>
    queryFn<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">fetchUser</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token operator">...</span>cacheConfig<span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>query<span class="token punctuation">.</span>isLoading<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>profile-loading<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Loader</span> <span class="token attr-name">size</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>medium<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>infinite-spinner<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Loading <span class="token punctuation">{</span>title<span class="token punctuation">}</span><span class="token operator">...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>query<span class="token punctuation">.</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>error<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Error<span class="token punctuation">:</span> <span class="token punctuation">{</span>query<span class="token punctuation">.</span>error<span class="token punctuation">.</span>message<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>user-profile<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h3</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>title<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h3</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">{</span>query<span class="token punctuation">.</span>isFetching <span class="token operator">?</span> <span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>background-loading<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Loader</span> <span class="token attr-name">size</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>small<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>pulsing<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>Updating<span class="token operator">...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>status-indicator<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Ready<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">)</span><span class="token punctuation">}</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h4</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>query<span class="token punctuation">.</span>data<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h4</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Email<span class="token punctuation">:</span> <span class="token punctuation">{</span>query<span class="token punctuation">.</span>data<span class="token punctuation">.</span>email<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Company<span class="token punctuation">:</span> <span class="token punctuation">{</span>query<span class="token punctuation">.</span>data<span class="token punctuation">.</span>company<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">ProfileDemo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>showProfiles<span class="token punctuation">,</span> setShowProfiles<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>comparison-container<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setShowProfiles</span><span class="token punctuation">(</span><span class="token operator">!</span>showProfiles<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token punctuation">{</span>showProfiles <span class="token operator">?</span> <span class="token string">'Hide'</span> <span class="token punctuation">:</span> <span class="token string">'Show'</span><span class="token punctuation">}</span> All Profiles
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Button</span><span class="token punctuation">&gt;</span></span>
      
      <span class="token punctuation">{</span>showProfiles <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>profiles-grid<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>UserProfile</span>
            <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Default Caching<span class="token punctuation">"</span></span>
            <span class="token attr-name">cacheConfig</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">}</span></span>
          <span class="token punctuation">/&gt;</span></span>
          
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>UserProfile</span>
            <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>With StaleTime (1 min)<span class="token punctuation">"</span></span>
            <span class="token attr-name">cacheConfig</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> staleTime<span class="token punctuation">:</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">1000</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span>
          <span class="token punctuation">/&gt;</span></span>
          
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>UserProfile</span>
            <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>No Cache (gcTime: 0)<span class="token punctuation">"</span></span>
            <span class="token attr-name">cacheConfig</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> gcTime<span class="token punctuation">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span>
          <span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">)</span><span class="token punctuation">}</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Now our enhanced <code>ProfileDemo</code> shows three different caching strategies using the same user data:</p><ol><li><strong>Default Caching</strong>: Instant display with background refetch (we&rsquo;ll see &ldquo;Updating&hellip;&rdquo; briefly)</li><li><strong>With StaleTime (1 min)</strong>: Instant display, no refetch for 1 minute (shows &ldquo;Ready&rdquo; status)</li><li><strong>No Cache</strong>: Always shows loading spinner when toggled because data is immediately garbage collected</li></ol><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-09/tanstack-query-comparison.gif?sfvrsn=c1fb94dd_2" alt="" /></p><h2 id="advanced-cache-configuration">Advanced Cache Configuration</h2><p>For more complex scenarios, we can configure additional caching behaviors:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">function</span> <span class="token function">AdvancedCacheExample</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> query <span class="token operator">=</span> <span class="token function">useQuery</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    queryKey<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'advanced-cache-example'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    queryFn<span class="token punctuation">:</span> fetchUser<span class="token punctuation">,</span>
    
    <span class="token comment">// Cache configuration</span>
    staleTime<span class="token punctuation">:</span> <span class="token number">5</span> <span class="token operator">*</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">,</span>     <span class="token comment">// 5 minutes fresh</span>
    gcTime<span class="token punctuation">:</span> <span class="token number">10</span> <span class="token operator">*</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">,</span>       <span class="token comment">// 10 minutes in cache</span>
    
    <span class="token comment">// Refetch configuration  </span>
    refetchOnMount<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>          <span class="token comment">// Refetch when component mounts</span>
    refetchOnWindowFocus<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>   <span class="token comment">// Don't refetch on window focus</span>
    refetchOnReconnect<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>      <span class="token comment">// Refetch when network reconnects</span>
    
    <span class="token comment">// Retry configuration</span>
    retry<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span>                      <span class="token comment">// Retry failed requests 3 times</span>
    retryDelay<span class="token punctuation">:</span> attemptIndex <span class="token operator">=&gt;</span> Math<span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">1000</span> <span class="token operator">*</span> <span class="token number">2</span> <span class="token operator">**</span> attemptIndex<span class="token punctuation">,</span> <span class="token number">30000</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Component implementation...</span>
<span class="token punctuation">}</span>
</code></pre><p>These additional options, like <code>refetchOnMount</code>, <code>refetchOnWindowFocus</code> and <code>retry</code>, give us granular control over when and how our data is fetched and cached.</p><h2 id="global-cache-configuration">Global Cache Configuration</h2><p>We can set default cache behavior globally when creating our <code>QueryClient</code>:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">const</span> queryClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">QueryClient</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  defaultOptions<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    queries<span class="token punctuation">:</span> <span class="token punctuation">{</span>
      staleTime<span class="token punctuation">:</span> <span class="token number">2</span> <span class="token operator">*</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">,</span>     <span class="token comment">// 2 minutes default staleTime</span>
      gcTime<span class="token punctuation">:</span> <span class="token number">10</span> <span class="token operator">*</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">,</span>       <span class="token comment">// 10 minutes default gcTime</span>
      refetchOnWindowFocus<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>   <span class="token comment">// Disable refetch on window focus globally</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>This approach lets us set sensible defaults for our entire application while still allowing per-query overrides when needed.</p><h2 id="wrap-up">Wrap-up</h2><p>TanStack Query&rsquo;s caching system transforms how we handle server state in React applications. Intelligently managing when to show cached data and when to fetch fresh data creates a responsive user experience that feels instant while keeping information up to date.</p><p>Combined with loading indicators like the KendoReact Loader component, we can create professional applications that handle the complexities of server state gracefully.</p><p>For more information, be sure to check out the official documentation:</p><ul><li><a target="_blank" href="https://tanstack.com/query/latest/docs/framework/react/guides/caching">TanStack Query Caching Guide</a></li><li><a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/indicators/loader/">KendoReact Loader Documentation</a></li></ul><hr /><p>Don&rsquo;t forget: The KendoReact Loader is free to use, even in production.</p><p><a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/free" class="Btn">Download KendoReact Free</a></p><img src="https://feeds.telerik.com/link/23056/17243869.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:bc29ae53-8373-467d-ad51-82deb9883636</id>
    <title type="text">An Introduction to Zustand</title>
    <summary type="text">Learn about state management library Zustand and see a practical UI demo using the Progress KendoReact Switch component to toggle a global theme.</summary>
    <published>2025-12-26T14:45:03Z</published>
    <updated>2026-04-23T22:50:00Z</updated>
    <author>
      <name>Hassan Djirdeh </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23056/17242041/introduction-zustand"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn about state management library Zustand and see a practical UI demo using the Progress KendoReact Switch component to toggle a global theme.</span></p><p>State management in React applications has evolved over the years. While <a target="_blank" href="https://redux.js.org/">Redux</a> dominated the landscape for a long time, developers have been seeking simpler, more lightweight alternatives that don&rsquo;t sacrifice power for convenience.</p><p>According to the recent <a target="_blank" href="https://2024.stateofreact.com/en-US/libraries/state-management/">State of React 2024</a> survey, Zustand has emerged as a growing favorite with 42% usage, up from 28% in 2023. In this article, we&rsquo;ll cover what makes Zustand appealing, how to set it up, and a practical UI demo using the Progress <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/inputs/switch">KendoReact Switch component</a> to toggle a global theme.</p><h2 id="zustand">Zustand</h2><p><a target="_blank" href="https://zustand.docs.pmnd.rs/getting-started/introduction">Zustand</a> is a small state management library that provides a simple, hook-based API for managing global state in React applications. Unlike Redux, which requires actions, reducers and more boilerplate code, Zustand lets you create stores with just a few lines of code while still being powerful enough to handle complex state scenarios.</p><h2 id="why-choose-zustand-over-other-solutions">Why Choose Zustand Over Other Solutions?</h2><p>Before diving into how Zustand works, let&rsquo;s understand why you might choose it over other state management solutions. Compared to React&rsquo;s built-in <a target="_blank" href="https://react.dev/reference/react/useState">useState</a> and <a target="_blank" href="https://react.dev/reference/react/useContext">useContext</a> hooks, Zustand offers better performance since components only rerender when the specific state they subscribe to changes.</p><p>Compared to Redux, Zustand offers a smaller learning curve, making it easier to understand and implement.</p><p>That said, you should stick with <code>useState</code> and <code>useContext</code> for simple applications with minimal state sharing needs!</p><h2 id="creating-your-first-store">Creating Your First Store</h2><p>To get started with Zustand, first install it in our React project:</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">npm</span> <span class="token function">install</span> zustand
</code></pre><p>Once installed, we can immediately start creating stores and using them in our components.</p><p>The core concept in Zustand is the <a target="_blank" href="https://zustand.docs.pmnd.rs/guides/flux-inspired-practice#single-store">store</a>, a hook that contains your state and the functions to update it. Let&rsquo;s create a simple example using a theme toggle feature with the React Switch component from the <a target="_blank" href="https://www.telerik.com/kendo-react-ui">Progress KendoReact UI library</a>.</p><p>We&rsquo;ll install the KendoReact Switch component from the <code>@progress/kendo-react-inputs</code> package:</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">npm</span> <span class="token function">install</span> @progress/kendo-react-inputs
</code></pre><p>Now, we&rsquo;ll create a simple theme store:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> create <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'zustand'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> useThemeStore <span class="token operator">=</span> <span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">set</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
  isDarkMode<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
  toggleTheme<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">set</span><span class="token punctuation">(</span><span class="token punctuation">(</span>state<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> isDarkMode<span class="token punctuation">:</span> <span class="token operator">!</span>state<span class="token punctuation">.</span>isDarkMode <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  setTheme<span class="token punctuation">:</span> <span class="token punctuation">(</span>isDark<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">set</span><span class="token punctuation">(</span><span class="token punctuation">{</span> isDarkMode<span class="token punctuation">:</span> isDark <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In this example, we&rsquo;re creating a store that manages a theme state. The <code>create</code> function takes a function that receives a <code>set</code> function, which we use to update the store&rsquo;s state. Our store contains:</p><ul><li><code>isDarkMode</code>: A boolean state indicating whether dark mode is enabled</li><li><code>toggleTheme</code>: A function that flips the current theme state</li><li><code>setTheme</code>: A function that sets the theme to a specific value</li></ul><h2 id="using-the-store-in-components">Using the Store in Components</h2><p>We can now create a component that uses our theme store with the KendoReact Switch:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Switch <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-inputs'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useThemeStore <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./store'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">ThemeToggle</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> isDarkMode<span class="token punctuation">,</span> toggleTheme <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useThemeStore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> 
      padding<span class="token punctuation">:</span> <span class="token string">'20px'</span><span class="token punctuation">,</span> 
      backgroundColor<span class="token punctuation">:</span> isDarkMode <span class="token operator">?</span> <span class="token string">'#333'</span> <span class="token punctuation">:</span> <span class="token string">'#fff'</span><span class="token punctuation">,</span>
      color<span class="token punctuation">:</span> isDarkMode <span class="token operator">?</span> <span class="token string">'#fff'</span> <span class="token punctuation">:</span> <span class="token string">'#333'</span><span class="token punctuation">,</span>
      borderRadius<span class="token punctuation">:</span> <span class="token string">'8px'</span><span class="token punctuation">,</span>
      margin<span class="token punctuation">:</span> <span class="token string">'20px'</span>
    <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>h3<span class="token operator">&gt;</span>Theme Settings<span class="token operator">&lt;</span><span class="token operator">/</span>h3<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> display<span class="token punctuation">:</span> <span class="token string">'flex'</span><span class="token punctuation">,</span> alignItems<span class="token punctuation">:</span> <span class="token string">'center'</span><span class="token punctuation">,</span> gap<span class="token punctuation">:</span> <span class="token string">'10px'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>span<span class="token operator">&gt;</span>Light Mode<span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>Switch 
          checked<span class="token operator">=</span><span class="token punctuation">{</span>isDarkMode<span class="token punctuation">}</span>
          onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">toggleTheme</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
          onLabel<span class="token operator">=</span><span class="token string">""</span>
          offLabel<span class="token operator">=</span><span class="token string">"☀️"</span>
        <span class="token operator">/</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>span<span class="token operator">&gt;</span>Dark Mode<span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>p<span class="token operator">&gt;</span>Current theme<span class="token punctuation">:</span> <span class="token punctuation">{</span>isDarkMode <span class="token operator">?</span> <span class="token string">'Dark'</span> <span class="token punctuation">:</span> <span class="token string">'Light'</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> ThemeToggle<span class="token punctuation">;</span>
</code></pre><p>The component destructures <code>isDarkMode</code> and <code>toggleTheme</code> from our store and uses the theme state to style the container conditionally. The KendoReact Switch component is used to toggle between light and dark modes with sun and moon emojis.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-09//zustand-theme-toggle.gif" alt="" /></p><h2 id="creating-a-more-complex-example">Creating a More Complex Example</h2><p>Let&rsquo;s build a more comprehensive example that demonstrates more of Zustand&rsquo;s capabilities. We&rsquo;ll create a user preferences store that manages multiple settings:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> create <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'zustand'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> usePreferencesStore <span class="token operator">=</span> <span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">set</span><span class="token punctuation">,</span> <span class="token keyword">get</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token comment">// State</span>
  user<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    name<span class="token punctuation">:</span> <span class="token string">'Guest'</span><span class="token punctuation">,</span>
    email<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  settings<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    notifications<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    autoSave<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
    darkMode<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
    language<span class="token punctuation">:</span> <span class="token string">'en'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  
  <span class="token comment">// Actions</span>
  updateUser<span class="token punctuation">:</span> <span class="token punctuation">(</span>userData<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">set</span><span class="token punctuation">(</span><span class="token punctuation">(</span>state<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
    user<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token operator">...</span>state<span class="token punctuation">.</span>user<span class="token punctuation">,</span> <span class="token operator">...</span>userData <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  
  toggleSetting<span class="token punctuation">:</span> <span class="token punctuation">(</span>settingKey<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">set</span><span class="token punctuation">(</span><span class="token punctuation">(</span>state<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
    settings<span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token operator">...</span>state<span class="token punctuation">.</span>settings<span class="token punctuation">,</span>
      <span class="token punctuation">[</span>settingKey<span class="token punctuation">]</span><span class="token punctuation">:</span> <span class="token operator">!</span>state<span class="token punctuation">.</span>settings<span class="token punctuation">[</span>settingKey<span class="token punctuation">]</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  
  updateSettings<span class="token punctuation">:</span> <span class="token punctuation">(</span>newSettings<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">set</span><span class="token punctuation">(</span><span class="token punctuation">(</span>state<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
    settings<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token operator">...</span>state<span class="token punctuation">.</span>settings<span class="token punctuation">,</span> <span class="token operator">...</span>newSettings <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  
  resetPreferences<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">set</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    user<span class="token punctuation">:</span> <span class="token punctuation">{</span> name<span class="token punctuation">:</span> <span class="token string">'Guest'</span><span class="token punctuation">,</span> email<span class="token punctuation">:</span> <span class="token string">''</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    settings<span class="token punctuation">:</span> <span class="token punctuation">{</span>
      notifications<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
      autoSave<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
      darkMode<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
      language<span class="token punctuation">:</span> <span class="token string">'en'</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  
  <span class="token comment">// Computed values</span>
  getDisplayName<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> state <span class="token operator">=</span> <span class="token keyword">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> state<span class="token punctuation">.</span>user<span class="token punctuation">.</span>name <span class="token operator">||</span> <span class="token string">'Anonymous User'</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>This store demonstrates a more complex structure with nested state objects for user data and settings. We define multiple actions to handle different types of updates and include a computed value using the <code>get</code> function.</p><p>We&rsquo;ll now create a comprehensive settings panel component with the help of the KendoReact Switch component:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Switch <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-inputs'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> usePreferencesStore <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./store'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">SettingsPanel</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> 
    settings<span class="token punctuation">,</span> 
    user<span class="token punctuation">,</span>
    toggleSetting<span class="token punctuation">,</span> 
    updateUser<span class="token punctuation">,</span>
    resetPreferences<span class="token punctuation">,</span>
    getDisplayName 
  <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">usePreferencesStore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> 
      padding<span class="token punctuation">:</span> <span class="token string">'20px'</span><span class="token punctuation">,</span> 
      maxWidth<span class="token punctuation">:</span> <span class="token string">'400px'</span><span class="token punctuation">,</span>
      backgroundColor<span class="token punctuation">:</span> settings<span class="token punctuation">.</span>darkMode <span class="token operator">?</span> <span class="token string">'#2d2d2d'</span> <span class="token punctuation">:</span> <span class="token string">'#f5f5f5'</span><span class="token punctuation">,</span>
      color<span class="token punctuation">:</span> settings<span class="token punctuation">.</span>darkMode <span class="token operator">?</span> <span class="token string">'#fff'</span> <span class="token punctuation">:</span> <span class="token string">'#333'</span><span class="token punctuation">,</span>
      borderRadius<span class="token punctuation">:</span> <span class="token string">'8px'</span><span class="token punctuation">,</span>
      fontFamily<span class="token punctuation">:</span> <span class="token string">'Arial, sans-serif'</span>
    <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>h2<span class="token operator">&gt;</span>User Preferences<span class="token operator">&lt;</span><span class="token operator">/</span>h2<span class="token operator">&gt;</span>
      
      <span class="token punctuation">{</span><span class="token comment">/* User Info Section */</span><span class="token punctuation">}</span>
      <span class="token operator">&lt;</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> marginBottom<span class="token punctuation">:</span> <span class="token string">'20px'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>h3<span class="token operator">&gt;</span>Welcome<span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token function">getDisplayName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">!</span><span class="token operator">&lt;</span><span class="token operator">/</span>h3<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>input
          type<span class="token operator">=</span><span class="token string">"text"</span>
          placeholder<span class="token operator">=</span><span class="token string">"Enter your name"</span>
          value<span class="token operator">=</span><span class="token punctuation">{</span>user<span class="token punctuation">.</span>name<span class="token punctuation">}</span>
          onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">updateUser</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token punctuation">:</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
          style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span>
            padding<span class="token punctuation">:</span> <span class="token string">'8px'</span><span class="token punctuation">,</span>
            borderRadius<span class="token punctuation">:</span> <span class="token string">'4px'</span><span class="token punctuation">,</span>
            border<span class="token punctuation">:</span> <span class="token string">'1px solid #ccc'</span><span class="token punctuation">,</span>
            width<span class="token punctuation">:</span> <span class="token string">'100%'</span><span class="token punctuation">,</span>
            marginBottom<span class="token punctuation">:</span> <span class="token string">'10px'</span>
          <span class="token punctuation">}</span><span class="token punctuation">}</span>
        <span class="token operator">/</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>input
          type<span class="token operator">=</span><span class="token string">"email"</span>
          placeholder<span class="token operator">=</span><span class="token string">"Enter your email"</span>
          value<span class="token operator">=</span><span class="token punctuation">{</span>user<span class="token punctuation">.</span>email<span class="token punctuation">}</span>
          onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">updateUser</span><span class="token punctuation">(</span><span class="token punctuation">{</span> email<span class="token punctuation">:</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
          style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span>
            padding<span class="token punctuation">:</span> <span class="token string">'8px'</span><span class="token punctuation">,</span>
            borderRadius<span class="token punctuation">:</span> <span class="token string">'4px'</span><span class="token punctuation">,</span>
            border<span class="token punctuation">:</span> <span class="token string">'1px solid #ccc'</span><span class="token punctuation">,</span>
            width<span class="token punctuation">:</span> <span class="token string">'100%'</span>
          <span class="token punctuation">}</span><span class="token punctuation">}</span>
        <span class="token operator">/</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>

      <span class="token punctuation">{</span><span class="token comment">/* Settings Section */</span><span class="token punctuation">}</span>
      <span class="token operator">&lt;</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> marginBottom<span class="token punctuation">:</span> <span class="token string">'20px'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>h3<span class="token operator">&gt;</span>Settings<span class="token operator">&lt;</span><span class="token operator">/</span>h3<span class="token operator">&gt;</span>
        
        <span class="token operator">&lt;</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> marginBottom<span class="token punctuation">:</span> <span class="token string">'15px'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
          <span class="token operator">&lt;</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> display<span class="token punctuation">:</span> <span class="token string">'flex'</span><span class="token punctuation">,</span> justifyContent<span class="token punctuation">:</span> <span class="token string">'space-between'</span><span class="token punctuation">,</span> alignItems<span class="token punctuation">:</span> <span class="token string">'center'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>label<span class="token operator">&gt;</span>Dark Mode<span class="token operator">&lt;</span><span class="token operator">/</span>label<span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>Switch
              checked<span class="token operator">=</span><span class="token punctuation">{</span>settings<span class="token punctuation">.</span>darkMode<span class="token punctuation">}</span>
              onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">toggleSetting</span><span class="token punctuation">(</span><span class="token string">'darkMode'</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
              onLabel<span class="token operator">=</span><span class="token string">""</span>
              offLabel<span class="token operator">=</span><span class="token string">"☀️"</span>
            <span class="token operator">/</span><span class="token operator">&gt;</span>
          <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>

        <span class="token operator">&lt;</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> marginBottom<span class="token punctuation">:</span> <span class="token string">'15px'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
          <span class="token operator">&lt;</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> display<span class="token punctuation">:</span> <span class="token string">'flex'</span><span class="token punctuation">,</span> justifyContent<span class="token punctuation">:</span> <span class="token string">'space-between'</span><span class="token punctuation">,</span> alignItems<span class="token punctuation">:</span> <span class="token string">'center'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>label<span class="token operator">&gt;</span>Notifications<span class="token operator">&lt;</span><span class="token operator">/</span>label<span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>Switch
              checked<span class="token operator">=</span><span class="token punctuation">{</span>settings<span class="token punctuation">.</span>notifications<span class="token punctuation">}</span>
              onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">toggleSetting</span><span class="token punctuation">(</span><span class="token string">'notifications'</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
              onLabel<span class="token operator">=</span><span class="token string">""</span>
              offLabel<span class="token operator">=</span><span class="token string">""</span>
            <span class="token operator">/</span><span class="token operator">&gt;</span>
          <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>

        <span class="token operator">&lt;</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> marginBottom<span class="token punctuation">:</span> <span class="token string">'15px'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
          <span class="token operator">&lt;</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> display<span class="token punctuation">:</span> <span class="token string">'flex'</span><span class="token punctuation">,</span> justifyContent<span class="token punctuation">:</span> <span class="token string">'space-between'</span><span class="token punctuation">,</span> alignItems<span class="token punctuation">:</span> <span class="token string">'center'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>label<span class="token operator">&gt;</span>Auto Save<span class="token operator">&lt;</span><span class="token operator">/</span>label<span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>Switch
              checked<span class="token operator">=</span><span class="token punctuation">{</span>settings<span class="token punctuation">.</span>autoSave<span class="token punctuation">}</span>
              onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">toggleSetting</span><span class="token punctuation">(</span><span class="token string">'autoSave'</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
              onLabel<span class="token operator">=</span><span class="token string">""</span>
              offLabel<span class="token operator">=</span><span class="token string">""</span>
            <span class="token operator">/</span><span class="token operator">&gt;</span>
          <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>

      <span class="token operator">&lt;</span>button
        onClick<span class="token operator">=</span><span class="token punctuation">{</span>resetPreferences<span class="token punctuation">}</span>
        style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span>
          padding<span class="token punctuation">:</span> <span class="token string">'10px 20px'</span><span class="token punctuation">,</span>
          backgroundColor<span class="token punctuation">:</span> <span class="token string">'#ff4444'</span><span class="token punctuation">,</span>
          color<span class="token punctuation">:</span> <span class="token string">'white'</span><span class="token punctuation">,</span>
          border<span class="token punctuation">:</span> <span class="token string">'none'</span><span class="token punctuation">,</span>
          borderRadius<span class="token punctuation">:</span> <span class="token string">'4px'</span><span class="token punctuation">,</span>
          cursor<span class="token punctuation">:</span> <span class="token string">'pointer'</span>
        <span class="token punctuation">}</span><span class="token punctuation">}</span>
      <span class="token operator">&gt;</span>
        Reset to Defaults
      <span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> SettingsPanel<span class="token punctuation">;</span>
</code></pre><blockquote><p>For the sake of brevity, the code examples in this article use inline styles rather than separate stylesheets or styled-components.</p></blockquote><p>The component destructures multiple pieces of state and actions from the store and uses conditional styling based on the dark mode setting. The component connects three KendoReact Switch components to toggle different preferences with emoji labels.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-09//zustand-settings-panel.gif" alt="" /></p><h2 id="understanding-state-updates">Understanding State Updates</h2><p>One of Zustand&rsquo;s strengths is how it handles state updates. The <code>set</code> function automatically merges the new state with the existing state at the top level, similar to React&rsquo;s <code>setState</code>. However, for nested objects, we would need to handle the merging ourselves:</p><pre class=" language-js"><code class="prism  language-js"><span class="token comment">// This works for top-level properties</span>
<span class="token keyword">set</span><span class="token punctuation">(</span><span class="token punctuation">{</span> isDarkMode<span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// For nested objects, we need to spread</span>
<span class="token keyword">set</span><span class="token punctuation">(</span><span class="token punctuation">(</span>state<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
  settings<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span>state<span class="token punctuation">.</span>settings<span class="token punctuation">,</span>
    darkMode<span class="token punctuation">:</span> <span class="token boolean">true</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>We can also replace the entire state by passing <code>true</code> as the second parameter:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">set</span><span class="token punctuation">(</span>newState<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// This replaces the entire state</span>
</code></pre><h2 id="store-organization-and-best-practices">Store Organization and Best Practices</h2><p>Here are some good practices to keep in mind when working with Zustand stores in a large application.</p><h3 id="single-store-vs.-multiple-stores">1. Single Store vs. Multiple Stores</h3><p>Zustand doesn&rsquo;t enforce any particular pattern, but it&rsquo;s preferable to:</p><ul><li>Use a <a target="_blank" href="https://zustand.docs.pmnd.rs/guides/flux-inspired-practice#single-store">single store</a> for related state that might need to interact.</li><li>Split into multiple stores for completely independent features.</li></ul><pre class=" language-js"><code class="prism  language-js"><span class="token comment">// Good: Related user state in one store</span>
<span class="token keyword">const</span> useUserStore <span class="token operator">=</span> <span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">set</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
  profile<span class="token punctuation">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span>
  preferences<span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
  updateProfile<span class="token punctuation">:</span> <span class="token punctuation">(</span>data<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">set</span><span class="token punctuation">(</span><span class="token punctuation">(</span>state<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> profile<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token operator">...</span>state<span class="token punctuation">.</span>profile<span class="token punctuation">,</span> <span class="token operator">...</span>data <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  updatePreferences<span class="token punctuation">:</span> <span class="token punctuation">(</span>prefs<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">set</span><span class="token punctuation">(</span><span class="token punctuation">{</span> preferences<span class="token punctuation">:</span> prefs <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Good: Separate store for unrelated shopping cart state</span>
<span class="token keyword">const</span> useCartStore <span class="token operator">=</span> <span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">set</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
  items<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  total<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
  addItem<span class="token punctuation">:</span> <span class="token punctuation">(</span>item<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">set</span><span class="token punctuation">(</span><span class="token punctuation">(</span>state<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> 
    items<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token operator">...</span>state<span class="token punctuation">.</span>items<span class="token punctuation">,</span> item<span class="token punctuation">]</span><span class="token punctuation">,</span>
    total<span class="token punctuation">:</span> state<span class="token punctuation">.</span>total <span class="token operator">+</span> item<span class="token punctuation">.</span>price 
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><h3 id="store-slicing">2. Store Slicing</h3><p>For larger applications, we can also split our store into <a target="_blank" href="https://zustand.docs.pmnd.rs/guides/slices-pattern#slices-pattern">slices</a>:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> <span class="token function-variable function">createUserSlice</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">set</span><span class="token punctuation">,</span> <span class="token keyword">get</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
  user<span class="token punctuation">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span>
  setUser<span class="token punctuation">:</span> <span class="token punctuation">(</span>user<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">set</span><span class="token punctuation">(</span><span class="token punctuation">{</span> user <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  clearUser<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">set</span><span class="token punctuation">(</span><span class="token punctuation">{</span> user<span class="token punctuation">:</span> <span class="token keyword">null</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">createSettingsSlice</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">set</span><span class="token punctuation">,</span> <span class="token keyword">get</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
  settings<span class="token punctuation">:</span> <span class="token punctuation">{</span> theme<span class="token punctuation">:</span> <span class="token string">'light'</span><span class="token punctuation">,</span> notifications<span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  updateSettings<span class="token punctuation">:</span> <span class="token punctuation">(</span>newSettings<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">set</span><span class="token punctuation">(</span><span class="token punctuation">(</span>state<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
    settings<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token operator">...</span>state<span class="token punctuation">.</span>settings<span class="token punctuation">,</span> <span class="token operator">...</span>newSettings <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> useAppStore <span class="token operator">=</span> <span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token operator">...</span>a<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token operator">...</span><span class="token function">createUserSlice</span><span class="token punctuation">(</span><span class="token operator">...</span>a<span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token operator">...</span><span class="token function">createSettingsSlice</span><span class="token punctuation">(</span><span class="token operator">...</span>a<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><h3 id="actions-outside-the-store">3. Actions Outside the Store</h3><p>We can also define actions outside the store if we prefer:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> useCounterStore <span class="token operator">=</span> <span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
  count<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// External actions</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">increment</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> 
  useCounterStore<span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">(</span>state<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> count<span class="token punctuation">:</span> state<span class="token punctuation">.</span>count <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">decrement</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> 
  useCounterStore<span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">(</span>state<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> count<span class="token punctuation">:</span> state<span class="token punctuation">.</span>count <span class="token operator">-</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">reset</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> 
  useCounterStore<span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> count<span class="token punctuation">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><h2 id="wrap-up">Wrap-up</h2><p>Zustand represents a shift toward simplicity in React state management without sacrificing flexibility. Its hook-based API feels natural to React developers, while its performance characteristics and minimal boilerplate make it an excellent choice for both small projects and large applications.</p><p>For more information on Zustand and the KendoReact Switch component, be sure to check out the official documentation for these utilities:</p><ul><li><a target="_blank" href="https://zustand.docs.pmnd.rs/">Zustand documentation</a></li><li><a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/inputs/switch/">KendoReact Switch documentation</a></li></ul><blockquote><p>The KendoReact Switch is part of KendoReact Free&mdash;free to use, including in production, no sign-up or license required.</p><br /><p><a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/free" class="Btn">Download KendoReact Free</a></p></blockquote><img src="https://feeds.telerik.com/link/23056/17242041.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:314d0eff-aabb-4094-ad77-99dda449a770</id>
    <title type="text">Getting Started with KendoReact Localization</title>
    <summary type="text">Creating a React app for a global audience should include adapting the content to local contexts. See how KendoReact Localization can help.</summary>
    <published>2025-12-22T17:38:06Z</published>
    <updated>2026-04-23T22:50:00Z</updated>
    <author>
      <name>Hassan Djirdeh </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23056/17239865/getting-started-kendoreact-localization"/>
    <content type="text"><![CDATA[<p><span class="featured">Creating a React app for a global audience should include adapting the content to local contexts. See how KendoReact Localization can help.</span></p><p>Building applications for a global audience means more than just translating text; it also involves adapting content to local contexts. It consists of adapting layouts, date formats and number conventions to create a native experience for users, regardless of their location. This process is known as <a target="_blank" href="https://en.wikipedia.org/wiki/Language_localization">localization</a>, and it plays a crucial role in creating inclusive and user-friendly software.</p><p>In this article, we&rsquo;ll explore the Progress <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/intl/l10n">KendoReact Localization</a> package and see how it makes internationalization straightforward by providing message translation capabilities and right-to-left (RTL) support for your React applications.</p><blockquote><p>The KendoReact <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/intl/l10n">Localization</a> package is part of <a target="_blank" href="https://www.telerik.com/kendo-react-ui">KendoReact</a>, an enterprise-grade UI library with over 120 components for building polished, performant apps.</p></blockquote><h2 id="kendoreact-localization">KendoReact Localization</h2><p>The KendoReact Localization package handles two main aspects of internationalization: translating component messages and supporting right-to-left text direction. This means we can create applications that work naturally for users, whether they&rsquo;re reading English, Arabic or any other language our application needs to support.</p><p>Let&rsquo;s dive into an example to see how we can make a <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/grid">React Grid</a> component fluent in multiple languages.</p><h2 id="translating-component-messages">Translating Component Messages</h2><p>First, we need to provide the translation messages for the languages we want to support. The KendoReact library makes this easy with the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/intl/l10n/loading-messages">loadMessages</a> function, which associates a set of messages with a specific locale.</p><p>These messages are simple key-value pairs. For Spanish and Arabic, the message files would look like this:</p><pre class=" language-js"><code class="prism  language-js"><span class="token comment">// messages-es.js</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
  <span class="token string">'kendo.grid.noRecords'</span><span class="token punctuation">:</span> <span class="token string">'No hay registros disponibles'</span><span class="token punctuation">,</span>
  <span class="token comment">// ...</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre><pre class=" language-js"><code class="prism  language-js"><span class="token comment">// messages-ar.js</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
  <span class="token string">'kendo.grid.noRecords'</span><span class="token punctuation">:</span> <span class="token string">'لا توجد سجلات متاحة'</span><span class="token punctuation">,</span>
  <span class="token comment">// ...</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre><p>In the example below, we&rsquo;ll set up a Grid that can switch between English, Spanish and Arabic. We&rsquo;ll use a <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/dropdowns/dropdownlist">React DropDownList</a> to let the user select a language, and the <code>Grid</code> will update its content and internal messages (like pagination controls) accordingly.</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Grid<span class="token punctuation">,</span> GridColumn <span class="token keyword">as</span> Column <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-grid'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  IntlProvider<span class="token punctuation">,</span>
  LocalizationProvider<span class="token punctuation">,</span>
  loadMessages<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-intl'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> DropDownList <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-dropdowns'</span><span class="token punctuation">;</span>

<span class="token comment">// Mock message files for Spanish and Arabic</span>
<span class="token keyword">import</span> esMessages <span class="token keyword">from</span> <span class="token string">'./messages-es'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> arMessages <span class="token keyword">from</span> <span class="token string">'./messages-ar'</span><span class="token punctuation">;</span>

<span class="token comment">// Load the messages for each locale</span>
<span class="token function">loadMessages</span><span class="token punctuation">(</span>esMessages<span class="token punctuation">,</span> <span class="token string">'es-ES'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">loadMessages</span><span class="token punctuation">(</span>arMessages<span class="token punctuation">,</span> <span class="token string">'ar-SA'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Custom column titles for different languages</span>
<span class="token keyword">const</span> columnTitles <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token string">'en-US'</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    ProductID<span class="token punctuation">:</span> <span class="token string">'ID'</span><span class="token punctuation">,</span>
    ProductName<span class="token punctuation">:</span> <span class="token string">'Product Name'</span><span class="token punctuation">,</span>
    UnitPrice<span class="token punctuation">:</span> <span class="token string">'Unit Price'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token string">'es-ES'</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    ProductID<span class="token punctuation">:</span> <span class="token string">'ID'</span><span class="token punctuation">,</span>
    ProductName<span class="token punctuation">:</span> <span class="token string">'Nombre del producto'</span><span class="token punctuation">,</span>
    UnitPrice<span class="token punctuation">:</span> <span class="token string">'Precio unitario'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token string">'ar-SA'</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    ProductID<span class="token punctuation">:</span> <span class="token string">'معرف المنتج'</span><span class="token punctuation">,</span>
    ProductName<span class="token punctuation">:</span> <span class="token string">'اسم المنتج'</span><span class="token punctuation">,</span>
    UnitPrice<span class="token punctuation">:</span> <span class="token string">'سعر الوحدة'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">App</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>locale<span class="token punctuation">,</span> setLocale<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">'en-US'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> <span class="token function-variable function">handleLocaleChange</span> <span class="token operator">=</span> <span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">setLocale</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> languageOptions <span class="token operator">=</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span> text<span class="token punctuation">:</span> <span class="token string">'English'</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token string">'en-US'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> text<span class="token punctuation">:</span> <span class="token string">'Espa&ntilde;ol'</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token string">'es-ES'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> text<span class="token punctuation">:</span> <span class="token string">'العربية'</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token string">'ar-SA'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> titles <span class="token operator">=</span> columnTitles<span class="token punctuation">[</span>locale<span class="token punctuation">]</span> <span class="token operator">||</span> columnTitles<span class="token punctuation">[</span><span class="token string">'en-US'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>example-config<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Select Language<span class="token punctuation">:</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>DropDownList</span>
          <span class="token attr-name">data</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>languageOptions<span class="token punctuation">}</span></span>
          <span class="token attr-name">textField</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span>
          <span class="token attr-name">dataItemKey</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>value<span class="token punctuation">"</span></span>
          <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>languageOptions<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">(</span>l<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> l<span class="token punctuation">.</span>value <span class="token operator">===</span> locale<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
          <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleLocaleChange<span class="token punctuation">}</span></span>
        <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>LocalizationProvider</span> <span class="token attr-name">language</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>locale<span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>IntlProvider</span> <span class="token attr-name">locale</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>locale<span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span> <span class="token attr-name">style</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> height<span class="token punctuation">:</span> <span class="token string">'420px'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span> <span class="token attr-name">data</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Column</span>
              <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ProductID<span class="token punctuation">"</span></span>
              <span class="token attr-name">title</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>titles<span class="token punctuation">.</span>ProductID<span class="token punctuation">}</span></span>
              <span class="token attr-name">filterable</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token boolean">false</span><span class="token punctuation">}</span></span>
              <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>100px<span class="token punctuation">"</span></span>
            <span class="token punctuation">/&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Column</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ProductName<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>titles<span class="token punctuation">.</span>ProductName<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Column</span>
              <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>UnitPrice<span class="token punctuation">"</span></span>
              <span class="token attr-name">title</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>titles<span class="token punctuation">.</span>UnitPrice<span class="token punctuation">}</span></span>
              <span class="token attr-name">filter</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>numeric<span class="token punctuation">"</span></span>
              <span class="token attr-name">format</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{0:c}<span class="token punctuation">"</span></span>
            <span class="token punctuation">/&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>IntlProvider</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>LocalizationProvider</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span>
</code></pre><p>In this code, we first import <code>loadMessages</code>, <code>LocalizationProvider</code> and <code>IntlProvider</code>, and we load our Spanish and Arabic message files. The <code>locale</code> is stored in React state, which is updated by the <code>DropDownList</code>. The <code>Grid</code> and its <code>Column</code> components are wrapped in <code>LocalizationProvider</code> and <code>IntlProvider</code>, which pass the selected locale down.</p><p>This automatically translates built-in messages, like those in the filter menus or the pager. For custom text, like our column titles, we use a simple <code>columnTitles</code> object to look up the correct translation based on the current <code>locale</code>.</p><p>With this, we get a language selector that allows us to switch between English, Spanish and Arabic.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-10/kendoreact-localization-translation.gif?sfvrsn=ddca4e33_2" alt="" /></p><h2 id="right-to-left-rtl-support">Right-to-Left (RTL) Support</h2><p>Some languages, such as Arabic, are read from right to left. A proper localization strategy must also adapt the application&rsquo;s layout to accommodate these users. KendoReact components have built-in RTL support, which can be enabled by adding a <code>dir="rtl"</code> attribute to a parent element.</p><p>Let&rsquo;s extend our previous example. When the user selects Arabic (<code>'ar-SA'</code>), we&rsquo;ll not only translate the text but also flip the UI into RTL mode.</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Grid<span class="token punctuation">,</span> GridColumn <span class="token keyword">as</span> Column <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-grid'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  IntlProvider<span class="token punctuation">,</span>
  LocalizationProvider<span class="token punctuation">,</span>
  loadMessages<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-intl'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> DropDownList <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-react-dropdowns'</span><span class="token punctuation">;</span>

<span class="token comment">// Message files and column titles would be defined here as in the previous example...</span>
<span class="token keyword">import</span> esMessages <span class="token keyword">from</span> <span class="token string">'./messages-es'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> arMessages <span class="token keyword">from</span> <span class="token string">'./messages-ar'</span><span class="token punctuation">;</span>

<span class="token function">loadMessages</span><span class="token punctuation">(</span>esMessages<span class="token punctuation">,</span> <span class="token string">'es-ES'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">loadMessages</span><span class="token punctuation">(</span>arMessages<span class="token punctuation">,</span> <span class="token string">'ar-SA'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> columnTitles <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token string">'en-US'</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    ProductID<span class="token punctuation">:</span> <span class="token string">'ID'</span><span class="token punctuation">,</span>
    ProductName<span class="token punctuation">:</span> <span class="token string">'Product Name'</span><span class="token punctuation">,</span>
    UnitPrice<span class="token punctuation">:</span> <span class="token string">'Unit Price'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token string">'es-ES'</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    ProductID<span class="token punctuation">:</span> <span class="token string">'ID'</span><span class="token punctuation">,</span>
    ProductName<span class="token punctuation">:</span> <span class="token string">'Nombre del producto'</span><span class="token punctuation">,</span>
    UnitPrice<span class="token punctuation">:</span> <span class="token string">'Precio unitario'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token string">'ar-SA'</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    ProductID<span class="token punctuation">:</span> <span class="token string">'معرف المنتج'</span><span class="token punctuation">,</span>
    ProductName<span class="token punctuation">:</span> <span class="token string">'اسم المنتج'</span><span class="token punctuation">,</span>
    UnitPrice<span class="token punctuation">:</span> <span class="token string">'سعر الوحدة'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">App</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>locale<span class="token punctuation">,</span> setLocale<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">'en-US'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> isRtl <span class="token operator">=</span> locale <span class="token operator">===</span> <span class="token string">'ar-SA'</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> <span class="token function-variable function">handleLocaleChange</span> <span class="token operator">=</span> <span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">setLocale</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> languageOptions <span class="token operator">=</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span> text<span class="token punctuation">:</span> <span class="token string">'English'</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token string">'en-US'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> text<span class="token punctuation">:</span> <span class="token string">'Espa&ntilde;ol'</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token string">'es-ES'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> text<span class="token punctuation">:</span> <span class="token string">'العربية'</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token string">'ar-SA'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> titles <span class="token operator">=</span> columnTitles<span class="token punctuation">[</span>locale<span class="token punctuation">]</span> <span class="token operator">||</span> columnTitles<span class="token punctuation">[</span><span class="token string">'en-US'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">dir</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>isRtl <span class="token operator">?</span> <span class="token string">'rtl'</span> <span class="token punctuation">:</span> <span class="token string">'ltr'</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>example-config<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Select Language<span class="token punctuation">:</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>DropDownList</span>
          <span class="token attr-name">data</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>languageOptions<span class="token punctuation">}</span></span>
          <span class="token attr-name">textField</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span>
          <span class="token attr-name">dataItemKey</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>value<span class="token punctuation">"</span></span>
          <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>languageOptions<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">(</span>l<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> l<span class="token punctuation">.</span>value <span class="token operator">===</span> locale<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
          <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleLocaleChange<span class="token punctuation">}</span></span>
        <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>LocalizationProvider</span> <span class="token attr-name">language</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>locale<span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>IntlProvider</span> <span class="token attr-name">locale</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>locale<span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Grid</span> <span class="token attr-name">style</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> height<span class="token punctuation">:</span> <span class="token string">'420px'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span> <span class="token attr-name">data</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Column</span>
              <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ProductID<span class="token punctuation">"</span></span>
              <span class="token attr-name">title</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>titles<span class="token punctuation">.</span>ProductID<span class="token punctuation">}</span></span>
              <span class="token attr-name">filterable</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token boolean">false</span><span class="token punctuation">}</span></span>
              <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>100px<span class="token punctuation">"</span></span>
            <span class="token punctuation">/&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Column</span> <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ProductName<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>titles<span class="token punctuation">.</span>ProductName<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Column</span>
              <span class="token attr-name">field</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>UnitPrice<span class="token punctuation">"</span></span>
              <span class="token attr-name">title</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>titles<span class="token punctuation">.</span>UnitPrice<span class="token punctuation">}</span></span>
              <span class="token attr-name">filter</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>numeric<span class="token punctuation">"</span></span>
              <span class="token attr-name">format</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{0:c}<span class="token punctuation">"</span></span>
            <span class="token punctuation">/&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Grid</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>IntlProvider</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>LocalizationProvider</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span>
</code></pre><p>The key change here is the <code>dir</code> attribute on the root <code>div</code>. We check if the current <code>locale</code> is <code>'ar-SA'</code> and set <code>dir</code> to <code>'rtl'</code> if it is. This simple change is all that&rsquo;s needed for KendoReact components to reverse their layout, so column order, text alignment and component controls are all correctly displayed for right-to-left readers.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-10/kendoreact-localization-rtl.gif?sfvrsn=4d395b05_2" alt="" /></p><h2 id="wrap-up">Wrap-up</h2><p>The KendoReact Localization package offers a comprehensive and user-friendly solution for adapting your applications to a global audience. By combining message translation with seamless right-to-left support, we can create interfaces that feel natural and intuitive to users from any region.</p><p>For more details on the KendoReact Localization package, including additional configuration options and the complete list of available message keys, be sure to check out the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/globalization/localization">official documentation</a>.</p><p>And if you want to try it yourself, download the free 30-day trial.</p><p><a target="_blank" href="https://www.telerik.com/try/kendo-react-ui" class="Btn">Try Now</a></p><img src="https://feeds.telerik.com/link/23056/17239865.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:a24beb96-ff0b-4d09-bbfd-fd09f5cc5752</id>
    <title type="text">Automating Complex Workflow in Your Next.js Application with Inngest</title>
    <summary type="text">We’ll build a simple loan application with Next.js and Inngest, plus go over the tools that were used to orchestrate complex workflows before Inngest.</summary>
    <published>2025-12-18T15:01:27Z</published>
    <updated>2026-04-23T22:50:00Z</updated>
    <author>
      <name>Christian Nwamba </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23056/17237136/automating-complex-workflow-nextjs-application-inngest"/>
    <content type="text"><![CDATA[<p><span class="featured">We&rsquo;ll build a simple loan application with Next.js and Inngest, plus go over the tools that were used to orchestrate complex workflows before Inngest.</span></p><p>Inngest makes it easier to build complex workflows in your applications. A complex workflow is a structured, multi-step process that involves multiple teams, tools and approval stages. It often has dependencies and cross-functional handoffs between tasks.</p><p><a target="_blank" href="https://www.inngest.com/">Inngest</a> is an event-driven, durable workflow engine that allows you to run reliable code on any platform, including serverless. Integrating Inngest in your application allows you to run complex processes, reduce delays and handle failures, which makes complex processes modular, reliable and easier by allowing you to write your workflow as code.</p><p>In this article, we will go through how to simplify a complex application using Inngest. To do that, we will build a simple loan application with <a target="_blank" href="https://nextjs.org/">Next.js</a> and Inngest. We will also go over the tools that were used to orchestrate complex workflows before Inngest.</p><h2 id="prerequisite">Prerequisite</h2><p>To continue, you will need a basic knowledge of <a target="_blank" href="https://react.dev/">React</a>, <a target="_blank" href="https://nextjs.org/">Next.js</a>, <a target="_blank" href="https://www.typescriptlang.org/">Typescript</a> and <a target="_blank" href="https://tailwindcss.com/">Tailwind</a>. You also need to know how to use <a target="_blank" href="https://www.npmjs.com/">npm</a> and <a target="_blank" href="https://nodejs.org/en">Node.js</a>.</p><h2 id="before-inngest">Before Inngest</h2><p>Before Inngest, developers had to orchestrate workflows manually or automatically using complex setups. Some examples of these setups include message queues and job runners. Less common are cron jobs, serverless functions, workflow engines and a DIY approach. Message queues (e.g., RabbitMQ, Apache Kafka and Amazon SQS) handled the &ldquo;mail delivery&rdquo; between different sources.</p><p>Brokers had to be installed, monitored and kept healthy, and if a sudden spike in traffic happened, that would result in higher costs. Also, in most cases of managing a complex system, a hybrid setup of message brokers (e.g., RabbitMQ) and an event streaming platform (e.g., Apache Kafka) would be needed because one tool was rarely enough to handle the massive workload. So what started as a clean setup slowly became a messy web of connections.</p><p>Basically, Inngest can be used to avoid these complex setups, making management of a complex workflow easier to handle.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/using-workflow-management-tools.png?sfvrsn=62d79761_2" title="A hybrid approach to using workflow management tools in a distributed architecture" alt="A hybrid approach to using workflow management tools in a distributed architecture" /></p><p>The diagram above shows a hybrid approach to using workflow management tools in a distributed architecture. The client application sends a request to the API gateway, which is processed and sent to the appropriate workflow orchestrator. Depending on the requirements of the request, a specific orchestrator is triggered.</p><p>So, for example, if the requirement needs interaction with Amazon services, Amazon SQS can be used to manage that request. Or if the request is an event-driven action like video streaming, Apache Kafka will be used to manage the request. This orchestrator then routes the request to the specific service responsible for finalizing the request, which can be an in-house or external service.</p><h2 id="what-is-inngest">What Is Inngest?</h2><p>Inngest is an event-driven, workflow-as-code system that allows you to orchestrate highly reliable application processes without having to manage complex infrastructure, queues and application state.</p><p>You basically define what your workflow is in code, and the Inngest platform takes care of the infrastructure, queuing, observability and scaling, which is all powered by scheduled and background jobs written in TypeScript, Python or Go.</p><h2 id="features-of-inngest">Features of Inngest</h2><ul><li><strong>Events and triggers</strong>: This allows Inngest functions to run asynchronously in response to events from various sources. These triggers can be customized through filtering, delaying execution, batching events or handling multiple event types in a single function.</li><li><strong>Inngest function</strong>: This lets developers run reliable background logic, from simple jobs to complex workflows. It supports retries, scheduling and orchestration.</li><li><strong>Middleware</strong>: This lets you run code at different points in an Inngest client&rsquo;s lifecycle, such as during function execution or event sending.</li><li><strong>Realtime (developer preview)</strong>: Realtime lets you stream updates from Inngest functions directly to users, enabling live UIs and bi-directional workflows (e.g., human-in-the-loop). It&rsquo;s built into Inngest, so no extra infrastructure is needed. Inngest manages the WebSocket server and user connections.</li></ul><p>Inngest provides two options for production use: Inngest Cloud or Inngest open-source software. The open-source option is free, customizable and prevents vendor lock-in, but requires you to manage the underlying infrastructure. Inngest Cloud offers flexible tiers ranging from a free tier to multiple paid plans depending on your usage needs, and it handles infrastructure management for you.</p><h2 id="build-a-loan-application-with-next.js-and-inngest">Build a Loan Application with Next.js and Inngest</h2><p>Now that we understand what Inngest is and its key features, let&rsquo;s see it in action. In this project, we will simulate a loan application workflow that includes KYC verification, fraud detection, loan decision logic, user notifications and database updates. This shows how Inngest simplifies complex, multi-step processes that need to run reliably in sequence.</p><h2 id="project-setup">Project Setup</h2><p>To set up a Next.js application, run the following command in your terminal. We will use TypeScript, Tailwind CSS, the <code>src</code> directory and the app router setup for our project.</p><pre class=" language-shell"><code class="prism  language-shell">npx create-next-app@latest my-inngest-app
cd my-inngest-app
</code></pre><p>Next, run the following command to install the Inngest SDK in our project:</p><pre class=" language-shell"><code class="prism  language-shell">npm install inngest
</code></pre><h2 id="setting-up-your-development-environment">Setting Up Your Development Environment</h2><p>For this tutorial, we&rsquo;ll use Inngest&rsquo;s local development mode, which runs entirely on your machine and doesn&rsquo;t require an account. The local dev server provides a dashboard at <code>http://localhost:8288</code> where you can see your functions, events and logs.</p><blockquote><p>For production deployment, you would either sign up for Inngest Cloud at <a target="_blank" href="https://www.inngest.com">https://www.inngest.com</a> (free tier available) or self-host the open-source version</p></blockquote><p>Create a new file called <code>client.ts</code> in the <code>src/inngest/</code> directory of our root directory, and add the following to it to initialize our Inngest client:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Inngest <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"inngest"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> inngest <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Inngest</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> <span class="token string">"my-inngest-app"</span><span class="token punctuation">,</span> <span class="token comment">// unique name for your app</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In the code above, we instantiated the Inngest class (client) and passed in the unique ID of our app as a parameter to the class constructor. Think of the client as the connection between your app and Inngest. The ID is like a namespace that helps you distinguish events and functions if you have multiple apps. You&rsquo;ll use this client both to define functions and to send events.</p><h2 id="building-the-loan-features">Building the Loan Features</h2><p>To implement the loan features, we will be doing the following:</p><ul><li>Creating a workflow orchestration using the Inngest function</li><li>Syncing our app with Inngest</li><li>Creating an API that triggers the workflow by sending an event</li><li>Creating a user interface with a button to initiate the process (apply for loan)</li></ul><h2 id="create-a-workflow-orchestration-using-the-inngest-function">Create a Workflow Orchestration Using the Inngest Function</h2><p>Create another file called <code>loanApplication.ts</code> in your <code>src/inngest/functions/</code> directory and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token comment">// src/inngest/functions/loanApplication.ts</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> inngest <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"../client"</span><span class="token punctuation">;</span>

<span class="token comment">//Simulated helper functions. In a production application, these functions would call real KYC providers (like Onfido or Jumio), fraud detection APIs (like Sift or Stripe Radar), and actual database operations. For this tutorial, we're using simulated functions to focus on the Inngest workflow patterns.</span>

<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">verifyKYC</span><span class="token punctuation">(</span>userId<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`Verifying KYC for user </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>userId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">...`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span> status<span class="token punctuation">:</span> <span class="token string">"verified"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// simulate success</span>
<span class="token punctuation">}</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">detectFraud</span><span class="token punctuation">(</span>userId<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`Running fraud detection for user </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>userId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">...`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span> risk<span class="token punctuation">:</span> <span class="token string">"low"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// simulate low risk</span>
<span class="token punctuation">}</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">decideLoan</span><span class="token punctuation">(</span>kyc<span class="token punctuation">:</span> <span class="token keyword">any</span><span class="token punctuation">,</span> fraud<span class="token punctuation">:</span> <span class="token keyword">any</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Deciding loan status..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>kyc<span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token string">"verified"</span> <span class="token operator">&amp;&amp;</span> fraud<span class="token punctuation">.</span>risk <span class="token operator">===</span> <span class="token string">"low"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token string">"approved"</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> <span class="token string">"rejected"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">notifyUser</span><span class="token punctuation">(</span>userId<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">,</span> decision<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`Notifying user </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>userId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: Loan </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>decision<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token keyword">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">updateDatabase</span><span class="token punctuation">(</span>userId<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">,</span> decision<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`Updating DB for user </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>userId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> with loan: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>decision<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token keyword">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Main loan application workflow function</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> loanApplicationFn <span class="token operator">=</span> inngest<span class="token punctuation">.</span><span class="token function">createFunction</span><span class="token punctuation">(</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token string">"loan-application"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// function metadata</span>
  <span class="token punctuation">{</span> event<span class="token punctuation">:</span> <span class="token string">"app/loan.submitted"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// trigger event</span>
  <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> event<span class="token punctuation">,</span> step <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> userId <span class="token operator">=</span> event<span class="token punctuation">.</span>data<span class="token punctuation">.</span>userId<span class="token punctuation">;</span>
    <span class="token comment">// Step 1: Verify KYC</span>
    <span class="token keyword">const</span> kyc <span class="token operator">=</span> <span class="token keyword">await</span> step<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token string">"verify-kyc"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">verifyKYC</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// Step 2: Fraud Detection</span>
    <span class="token keyword">const</span> fraud <span class="token operator">=</span> <span class="token keyword">await</span> step<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token string">"fraud-detection"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">detectFraud</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// Step 3: Loan Decision</span>
    <span class="token keyword">const</span> decision <span class="token operator">=</span> <span class="token keyword">await</span> step<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token string">"loan-decision"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
      <span class="token function">decideLoan</span><span class="token punctuation">(</span>kyc<span class="token punctuation">,</span> fraud<span class="token punctuation">)</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// Step 4: Notify User</span>
    <span class="token keyword">await</span> step<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token string">"notify-user"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">notifyUser</span><span class="token punctuation">(</span>userId<span class="token punctuation">,</span> decision<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// Step 5: Update Database</span>
    <span class="token keyword">await</span> step<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token string">"update-db"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">updateDatabase</span><span class="token punctuation">(</span>userId<span class="token punctuation">,</span> decision<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`Loan </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>decision<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> for user </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>userId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In the code snippet above, we created a workflow for our loan application using the <code>inngest.createFunction()</code> function. We passed in a metadata object <code>{id: "loan-application"}</code>, which is a unique identifier for the function. We also passed an event definition that triggers the function, which is an object called <code>{event: "app/loan.submitted"}</code>. This is used by the API in our application to trigger our loan workflow written in the <code>loanApplicationFn</code> function.</p><p>The first action in our workflow is the <code>verifyKYC</code> function, which verifies the authenticity of the user either using an in-house solution or an external KYC provider. Next is our <code>detectFraud</code> function that handles fraudulent activities and verifies the loan request is free from dubious actions.</p><p>Then we initiated the <code>decideLoan</code> function, which runs the requirements to decide whether the loan should be approved or not. The <code>notifyUser</code> function then runs to perform all necessary client updates, like user interface updates, email notifications, etc. Finally, we update the database with all the needed information for data persistence using the <code>updateDatabase</code> function.</p><p>Lastly, we execute the appropriate functions that contain the business requirements using the <code>step.run()</code> function. In our <code>loanApplicationFn</code>, the <code>step.run()</code> function is used to run every function from <code>verifyKYC</code> to <code>updateDatabase</code>, which then allows the Inngest platform to track progress, handle retries, logging and failures, helping everything go as planned.</p><p>Note that a function run in the workflow can share data by simply returning a value, which can be passed into the next function to be executed with <code>step.run()</code>.</p><h2 id="syncing-our-app-with-inngest">Syncing Our App with Inngest</h2><p>Create a <code>route.ts</code> file in the <code>src/api/inngest</code> directory, and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> serve <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"inngest/next"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> inngest <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/inngest/client"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> loanApplicationFn <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/inngest/functions/loanApplication"</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> GET<span class="token punctuation">,</span> POST<span class="token punctuation">,</span> PUT <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">serve</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  client<span class="token punctuation">:</span> inngest<span class="token punctuation">,</span>
  functions<span class="token punctuation">:</span> <span class="token punctuation">[</span>loanApplicationFn<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The code above syncs our Next.js app with Inngest.</p><p>Now run this command in your terminal to start our Inngest local server:</p><pre class=" language-shell"><code class="prism  language-shell">npx inngest-cli@latest dev
</code></pre><p>You&rsquo;ll be able to see our app in the dashboard by navigating to the <strong>Apps</strong> tab.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/inngest-dashboard.png?sfvrsn=3c33cc35_2" title="Inngest dashboard" alt="Inngest dashboard" /></p><p>In the image above, you can see the <code>my-inngest-app</code> app under <strong>Synced Apps</strong>. You&rsquo;ll also be able to see logs, retries and execution history in the Inngest Dev dashboard by visiting <a target="_blank" href="http://localhost:8288">http://localhost:8288</a>.</p><h2 id="create-an-api-that-triggers-the-workflow-by-sending-an-event">Create an API That Triggers the Workflow by Sending an Event</h2><p>Create an API route in this directory path: <code>src/app/api/send-event/route.ts</code> and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> NextResponse <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"next/server"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> inngest <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"../../../inngest/client"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">POST</span><span class="token punctuation">(</span>request<span class="token punctuation">:</span> Request<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> body <span class="token operator">=</span> <span class="token keyword">await</span> request<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">await</span> inngest<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    name<span class="token punctuation">:</span> <span class="token string">"app/loan.submitted"</span><span class="token punctuation">,</span>
    data<span class="token punctuation">:</span> <span class="token punctuation">{</span> userId<span class="token punctuation">:</span> body<span class="token punctuation">.</span>userId <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> NextResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> status<span class="token punctuation">:</span> <span class="token string">"ok"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>In the code above, we create a <code>POST</code> endpoint that can be used to trigger the event <code>app/loan.submitted</code> with an event data object containing the <code>userId</code> from the request body.</p><p>The event name <code>app/loan.submitted</code> is a signal Inngest listens for. When we set up our function earlier, we basically told Inngest, "Hey, whenever you catch an event called <code>app/loan.submitted</code>, go ahead and run the function <code>loanApplicationFn</code>".</p><h2 id="creating-a-user-interface-with-a-button-to-initiate-the-process-apply-for-a-loan">Creating a User Interface with a Button to Initiate the Process (Apply for a Loan)</h2><p>Add the following code to your <code>src/app/page.tsx</code> file:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token string">"use client"</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Home</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> sendEvent <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"/api/send-event"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
      method<span class="token punctuation">:</span> <span class="token string">"POST"</span><span class="token punctuation">,</span>
      headers<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"Content-Type"</span><span class="token punctuation">:</span> <span class="token string">"application/json"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      body<span class="token punctuation">:</span> JSON<span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span> userId<span class="token punctuation">:</span> <span class="token number">125485</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Event sent!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>main</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>p-8<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-xl<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Inngest <span class="token operator">+</span> Next<span class="token punctuation">.</span>js<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>sendEvent<span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span>Apply <span class="token keyword">for</span> Loan<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>main</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>In the code above, we create a simple button called <code>Apply for Loan</code>. When this button is clicked, it calls the <code>send-event</code> API with a body object that contains userId set to 125485, which fires off an event that gets sent to Inngest and gets handled in the background.</p><p>Now, run the following command in your terminal to start your Next.js server:</p><pre class=" language-shell"><code class="prism  language-shell">npm run dev
</code></pre><p>Next.js serves your app and API routes. The Inngest Dev server connects to <code>/api/inngest</code> and makes sure your events and functions work locally.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/loan-app.png?sfvrsn=658a6125_2" title="Simple loan app user interface" alt="Simple loan app user interface" /></p><p>You can click on the <strong>Apply for Loan</strong> button to trigger the event.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/app-user-interface-with-event-trigger.png?sfvrsn=344ed95a_2" title="App user interface with an event trigger" alt="App user interface with an event trigger" /></p><p>You should get an alert as shown above.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/list-of-triggered-event.png?sfvrsn=7bd2d1e3_2" title="Inngest dashboard showing list of triggered events" alt="Inngest dashboard showing list of triggered events" /></p><p>When you navigate to the <strong>Events</strong> tab on your Inngest dashboard, you should see the <code>app/loan.submitted</code> event has been added to your list as shown above.</p><h2 id="conclusion">Conclusion</h2><p>In this article, we explored how Inngest simplifies complex workflow orchestration by treating workflows as code. Traditional approaches to managing complex workflows can become a tangled web of connections that are difficult to scale and manage.</p><p>Inngest changes this by providing an event-driven, durable workflow engine that handles infrastructure concerns automatically. This allows you to focus on writing your business logic while the platform manages retries, failure recovery, execution tracking and scaling.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Task Automation in Next.js Using CopilotKit</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Let&rsquo;s <a target="_blank" href="https://www.telerik.com/blogs/task-automation-nextjs-using-copilotkit"> explore the CopilotKit</a>, an open-source framework not just for generating content or ideas but also for working side by side with your users to automate tasks and get things done faster and easier.</p></div></div></aside><img src="https://feeds.telerik.com/link/23056/17237136.gif" height="1" width="1"/>]]></content>
  </entry>
</feed>
