CINXE.COM
Using AG Grid with Next.js to Build a React Table
<!DOCTYPE html> <html lang="en"> <head> <!-- Google Tag Manager --> <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-T7JG534');</script> <!-- End Google Tag Manager --> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <title>Using AG Grid with Next.js to Build a React Table</title> <meta name="HandheldFriendly" content="True" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script type="text/javascript" src="https://blog.ag-grid.com/assets/built/prism.js?v=8a9360074a"></script> <link rel="stylesheet" type="text/css" href="https://blog.ag-grid.com/assets/built/screen.css?v=8a9360074a" /> <meta name="description" content="Learn how to integrate AG Grid with Next.js, install your license key, and use advanced features like the Server-Side Row Model and Integrated Charting."> <link rel="icon" href="https://blog.ag-grid.com/content/images/size/w256h256/2021/02/200pxArtboard-5.png" type="image/png"> <link rel="canonical" href="https://blog.ag-grid.com/using-ag-grid-with-next-js-to-build-a-react-table/"> <meta name="referrer" content="no-referrer-when-downgrade"> <link rel="amphtml" href="https://blog.ag-grid.com/using-ag-grid-with-next-js-to-build-a-react-table/amp/"> <meta property="og:site_name" content="AG Grid Blog"> <meta property="og:type" content="article"> <meta property="og:title" content="Using AG Grid with Next.js to Build a React Table"> <meta property="og:description" content="Learn how to integrate AG Grid with Next.js, install your license key, and use advanced features like the Server-Side Row Model and Integrated Charting."> <meta property="og:url" content="https://blog.ag-grid.com/using-ag-grid-with-next-js-to-build-a-react-table/"> <meta property="og:image" content="https://blog.ag-grid.com/content/images/size/w1200/2025/01/AG-Grid-Next-JS-React-Table-Tutorial.png"> <meta property="article:published_time" content="2025-01-07T14:19:16.000Z"> <meta property="article:modified_time" content="2025-01-09T17:09:39.000Z"> <meta property="article:tag" content="React"> <meta property="article:tag" content="How To"> <meta property="article:tag" content="Tutorial"> <meta property="article:publisher" content="https://www.facebook.com/aggridbalham"> <meta name="twitter:card" content="summary_large_image"> <meta name="twitter:title" content="Using AG Grid with Next.js to Build a React Table"> <meta name="twitter:description" content="Learn how to integrate AG Grid with Next.js, install your license key, and use advanced features like the Server-Side Row Model and Integrated Charting."> <meta name="twitter:url" content="https://blog.ag-grid.com/using-ag-grid-with-next-js-to-build-a-react-table/"> <meta name="twitter:image" content="https://blog.ag-grid.com/content/images/size/w1200/2025/01/AG-Grid-Next-JS-React-Table-Tutorial.png"> <meta name="twitter:label1" content="Written by"> <meta name="twitter:data1" content="Shadid Haque"> <meta name="twitter:label2" content="Filed under"> <meta name="twitter:data2" content="React, How To, Tutorial"> <meta name="twitter:site" content="@ag_grid"> <meta name="twitter:creator" content="@haqueshadid"> <meta property="og:image:width" content="1200"> <meta property="og:image:height" content="675"> <script type="application/ld+json"> { "@context": "https://schema.org", "@type": "Article", "publisher": { "@type": "Organization", "name": "AG Grid Blog", "url": "https://blog.ag-grid.com/", "logo": { "@type": "ImageObject", "url": "https://blog.ag-grid.com/content/images/2021/02/logo-white.svg", "width": 235, "height": 40 } }, "author": { "@type": "Person", "name": "Shadid Haque", "image": { "@type": "ImageObject", "url": "https://blog.ag-grid.com/content/images/2024/12/451103427_7799367756855946_4549416648696623054_n.jpg", "width": 958, "height": 960 }, "url": "https://blog.ag-grid.com/author/shadid/", "sameAs": [ "https://twitter.com/haqueshadid" ] }, "headline": "Using AG Grid with Next.js to Build a React Table", "url": "https://blog.ag-grid.com/using-ag-grid-with-next-js-to-build-a-react-table/", "datePublished": "2025-01-07T14:19:16.000Z", "dateModified": "2025-01-09T17:09:39.000Z", "image": { "@type": "ImageObject", "url": "https://blog.ag-grid.com/content/images/size/w1200/2025/01/AG-Grid-Next-JS-React-Table-Tutorial.png", "width": 1200, "height": 675 }, "keywords": "React, How To, Tutorial", "description": "Learn how to integrate AG Grid with Next.js, install your license key, and use advanced features like the Server-Side Row Model and Integrated Charting.", "mainEntityOfPage": "https://blog.ag-grid.com/using-ag-grid-with-next-js-to-build-a-react-table/" } </script> <meta name="generator" content="Ghost 5.109"> <link rel="alternate" type="application/rss+xml" title="AG Grid Blog" href="https://blog.ag-grid.com/rss/"> <script defer src="https://cdn.jsdelivr.net/ghost/portal@~2.49/umd/portal.min.js" data-i18n="true" data-ghost="https://blog.ag-grid.com/" data-key="e3288fd636f108208efe135083" data-api="https://ag-grid-blog.ghost.io/ghost/api/content/" data-locale="en" crossorigin="anonymous"></script><style id="gh-members-styles">.gh-post-upgrade-cta-content, .gh-post-upgrade-cta { display: flex; flex-direction: column; align-items: center; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; text-align: center; width: 100%; color: #ffffff; font-size: 16px; } .gh-post-upgrade-cta-content { border-radius: 8px; padding: 40px 4vw; } .gh-post-upgrade-cta h2 { color: #ffffff; font-size: 28px; letter-spacing: -0.2px; margin: 0; padding: 0; } .gh-post-upgrade-cta p { margin: 20px 0 0; padding: 0; } .gh-post-upgrade-cta small { font-size: 16px; letter-spacing: -0.2px; } .gh-post-upgrade-cta a { color: #ffffff; cursor: pointer; font-weight: 500; box-shadow: none; text-decoration: underline; } .gh-post-upgrade-cta a:hover { color: #ffffff; opacity: 0.8; box-shadow: none; text-decoration: underline; } .gh-post-upgrade-cta a.gh-btn { display: block; background: #ffffff; text-decoration: none; margin: 28px 0 0; padding: 8px 18px; border-radius: 4px; font-size: 16px; font-weight: 600; } .gh-post-upgrade-cta a.gh-btn:hover { opacity: 0.92; }</style> <script defer src="https://cdn.jsdelivr.net/ghost/sodo-search@~1.5/umd/sodo-search.min.js" data-key="e3288fd636f108208efe135083" data-styles="https://cdn.jsdelivr.net/ghost/sodo-search@~1.5/umd/main.css" data-sodo-search="https://ag-grid-blog.ghost.io/" data-locale="en" crossorigin="anonymous"></script> <link href="https://blog.ag-grid.com/webmentions/receive/" rel="webmention"> <script defer src="/public/cards.min.js?v=8a9360074a"></script> <link rel="stylesheet" type="text/css" href="/public/cards.min.css?v=8a9360074a"> <script defer src="/public/member-attribution.min.js?v=8a9360074a"></script><style>:root {--ghost-accent-color: #15171A;}</style> <!-- Google Tag Manager config in the template --> <script defer data-domain="blog.ag-grid.com" src="https://plausible.io/js/plausible.js"></script> <meta name="google-site-verification" content="HsYGuuU8IDov5MwlzKGT-ZlRGStBcr539sGhBYx-O-I" /> <meta name="google-site-verification" content="cgkypu-dfgpZwNHMkHsP3rIT2FSTlrCKZkz-OcGg1-Y" /> <script> const urlParams = new URLSearchParams(window.location.search); const htlmEl = document.documentElement; const getDarkMode = () => { if (urlParams.has('darkmode')) { return urlParams.get('darkmode') === 'true'; } else if (htlmEl.hasAttribute("data-dark-mode")) { return htlmEl.getAttribute("data-dark-mode") === "true"; } else if (localStorage.darkMode) { return localStorage.darkMode === "true"; } else { // OS level darkmode return ( window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ); } }; const setDarkMode = (darkmode) => { localStorage.darkMode = darkmode; // Using .no-transitions class so that there are no animations between light/dark modes htlmEl.classList.add("no-transitions"); htlmEl.setAttribute("data-dark-mode", darkmode); // Set darkmode for header & footer document .querySelectorAll(".darkmode-data-target") .forEach((el) => el.setAttribute("data-dark-mode", darkmode)); htlmEl.offsetHeight; // Trigger a reflow, flushing the CSS changes htlmEl.classList.remove("no-transitions"); }; // Set darkmode before DOM load setDarkMode(getDarkMode()); document.addEventListener("DOMContentLoaded", function () { setDarkMode(getDarkMode()); // Set darkmode again on DOM load to set header & footer darkmode const darkmodeToggle = document.getElementById("darkmode-toggle"); darkmodeToggle.addEventListener("click", () => { setDarkMode(!getDarkMode()); }); }); </script> </head> <body class="post-template tag-react-data-grid tag-how-to tag-tutorial"> <!-- Google Tag Manager (noscript) --> <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-T7JG534" height="0" width="0" style="display:none;visibility:hidden" ></iframe></noscript> <!-- End Google Tag Manager (noscript) --> <header class="site-header"> <div class="darkmode-data-target"> <div class="header"> <div class="headerInner layout-page-max-width"> <a id="grid-logo" class="headerLogo" href="https://www.ag-grid.com/" aria-label="Home"> <svg xmlns="http://www.w3.org/2000/svg" class="logotype" width="154" height="40" viewBox="0 0 154 40"> <style> .logotype path, .logotype rect { fill: #fff; } .logotype.dark-type > path, .logotype.dark-type > rect { fill: #003264; } </style> <path d="M147.979,5.6l-0,28.417l-4.768,-0l-0.127,-2.988c-0.7,1.017 -1.59,1.844 -2.67,2.479c-1.081,0.572 -2.416,0.89 -3.942,0.89c-1.335,0 -2.606,-0.254 -3.687,-0.699c-1.144,-0.509 -2.162,-1.144 -2.988,-2.034c-0.826,-0.89 -1.526,-1.971 -1.971,-3.179c-0.508,-1.208 -0.699,-2.606 -0.699,-4.132c-0,-1.526 0.254,-2.924 0.699,-4.196c0.509,-1.271 1.145,-2.352 1.971,-3.242c0.826,-0.89 1.844,-1.589 2.988,-2.098c1.144,-0.509 2.352,-0.763 3.687,-0.763c1.526,0 2.797,0.254 3.878,0.827c1.081,0.572 1.971,1.335 2.67,2.415l-0,-11.633l4.959,-0l-0,-0.064Zm-10.426,24.539c1.653,-0 2.924,-0.572 3.941,-1.653c1.017,-1.081 1.526,-2.543 1.526,-4.323c-0,-1.78 -0.509,-3.179 -1.526,-4.323c-1.017,-1.081 -2.288,-1.653 -3.941,-1.653c-1.59,0 -2.925,0.572 -3.878,1.653c-1.017,1.081 -1.526,2.543 -1.526,4.323c0,1.78 0.509,3.179 1.526,4.259c1.017,1.145 2.288,1.717 3.878,1.717"/> <rect x="119.067" y="5.6" width="4.959" height="5.849"/> <rect x="119.067" y="14.373" width="4.959" height="19.644"/> <path d="M108.831,16.979c1.59,-2.352 5.595,-2.606 7.248,-2.606l-0,4.577c-2.035,0 -4.069,0.064 -5.277,0.954c-1.208,0.89 -1.843,2.098 -1.843,3.56l-0,10.553l-4.959,-0l0,-19.644l4.768,-0l0.063,2.606Z"/> <path d="M26.489,28.677l-12.46,-0l-2.162,5.34l-5.467,-0l11.507,-26.955l4.768,0l11.506,26.955l-5.531,-0l-2.161,-5.34Zm-1.717,-4.26l-4.513,-10.998l-4.514,10.998l9.027,0Z"/> <path d="M62.024,18.654l-12.286,0l-0,4.267l6.963,0c-0.219,2.139 -1.021,3.846 -2.406,5.123c-1.385,1.276 -3.208,1.914 -5.469,1.914c-1.288,0 -2.461,-0.231 -3.518,-0.693c-1.058,-0.462 -1.964,-1.113 -2.717,-1.95c-0.753,-0.839 -1.337,-1.848 -1.749,-3.027c-0.414,-1.179 -0.62,-2.486 -0.62,-3.92c-0,-1.433 0.206,-2.739 0.62,-3.919c0.412,-1.178 0.996,-2.187 1.749,-3.026c0.753,-0.838 1.665,-1.488 2.734,-1.95c1.07,-0.462 2.248,-0.693 3.538,-0.693c2.669,-0 4.696,0.642 6.081,1.927l3.284,-3.286c-2.486,-1.934 -5.63,-2.907 -9.439,-2.907c-2.114,-0 -4.023,0.334 -5.723,1.002c-1.703,0.669 -3.161,1.605 -4.376,2.807c-1.216,1.204 -2.151,2.657 -2.807,4.357c-0.657,1.702 -0.985,3.599 -0.985,5.688c-0,2.066 0.334,3.957 1.003,5.67c0.668,1.714 1.61,3.173 2.825,4.375c1.216,1.204 2.673,2.139 4.375,2.808c1.702,0.668 3.597,1.002 5.688,1.002c2.042,0 3.883,-0.334 5.524,-1.002c1.64,-0.669 3.038,-1.604 4.193,-2.808c1.154,-1.202 2.042,-2.661 2.661,-4.375c0.621,-1.713 0.93,-3.604 0.93,-5.67c0,-0.291 -0.007,-0.577 -0.017,-0.856c-0.014,-0.28 -0.032,-0.565 -0.056,-0.858"/> <path d="M100.792,18.654l-12.286,0l-0,4.267l6.963,0c-0.219,2.139 -1.021,3.846 -2.406,5.123c-1.385,1.276 -3.208,1.914 -5.469,1.914c-1.288,0 -2.461,-0.231 -3.518,-0.693c-1.058,-0.462 -1.964,-1.113 -2.717,-1.95c-0.753,-0.839 -1.337,-1.848 -1.749,-3.027c-0.414,-1.179 -0.62,-2.486 -0.62,-3.92c-0,-1.433 0.206,-2.739 0.62,-3.919c0.412,-1.178 0.996,-2.187 1.749,-3.026c0.753,-0.838 1.665,-1.488 2.735,-1.95c1.069,-0.462 2.247,-0.693 3.537,-0.693c2.669,-0 4.697,0.642 6.081,1.927l3.284,-3.286c-2.486,-1.934 -5.63,-2.907 -9.438,-2.907c-2.115,-0 -4.024,0.334 -5.724,1.002c-1.703,0.669 -3.161,1.605 -4.376,2.807c-1.216,1.204 -2.151,2.657 -2.807,4.357c-0.657,1.702 -0.985,3.599 -0.985,5.688c-0,2.066 0.334,3.957 1.003,5.67c0.668,1.714 1.61,3.173 2.825,4.375c1.216,1.204 2.673,2.139 4.375,2.808c1.702,0.668 3.597,1.002 5.689,1.002c2.041,0 3.883,-0.334 5.523,-1.002c1.64,-0.669 3.038,-1.604 4.193,-2.808c1.154,-1.202 2.042,-2.661 2.661,-4.375c0.621,-1.713 0.93,-3.604 0.93,-5.67c0,-0.291 -0.007,-0.577 -0.017,-0.856c-0.014,-0.28 -0.032,-0.565 -0.056,-0.858"/> </svg><svg xmlns="http://www.w3.org/2000/svg" class="logomark" width="64" height="48" viewBox="0 0 64 48" > <style> .logomark .aqua { fill: #55b4c8; } .logomark .orange { fill: #ff8c00; } .logomark .red { fill: #f00; } .logomark .grey { fill: #b4bebe; } rect { animation-iteration-count: infinite; animation-timing-function: ease-in-out; animation-play-state: paused; } .right-2 { animation-delay: calc(1.25s / 6); } .right-3 { animation-delay: calc(1.25s / 6 * 2); } .left-3 { animation-delay: calc(1.25s / 6 * 3); } .left-2 { animation-delay: calc(1.25s / 6 * 4); } .left-1 { animation-delay: calc(1.25s / 6 * 5); } @keyframes logo-mark-bounce-right { 0% { transform: translateX(0%); } 16.6666% { transform: translateX(3px); } 33.3333% { transform: translateX(0); } } </style> <rect class="aqua right-1" x="51" y="10" width="7" height="8" /> <path class="aqua right-1" d="M58,10l-17,0l-8,8l25,0l0,-8Z" /> <rect class="orange right-2" x="36" y="22" width="7" height="8" /> <path class="orange right-2" d="M43,30l0,-7.995l-14,-0l-8.008,7.995l22.008,0Z" /> <rect class="red right-3" x="24" y="34" width="7" height="8" /> <path class="red right-3" d="M13,38.01l4,-4.01l14,0l0,8l-18,0l0,-3.99Z" /> <rect class="grey left-1" x="11" y="6" width="7" height="8" /> <path class="grey left-1" d="M41,10l-4,4l-26,0l0,-8l30,0l0,4Z" /> <rect class="grey left-2" x="16" y="18" width="7" height="8" /> <path class="grey left-2" d="M16,26l9,0l8,-8l-17,-0l0,8Z" /> <rect class="grey left-3" x="6" y="30" width="7" height="8" /> <path class="grey left-3" d="M6,37.988l7,0.012l7.992,-8l-14.992,-0.047l-0,8.035Z" /> </svg> </a> <button class="mobileMenuButton" type="button" aria-controls="main-nav" aria-expanded='false' aria-label="Toggle navigation" onclick="toggleMobileMenu()"; > <svg xmlns="http://www.w3.org/2000/svg" class="menuIcon menu-icon" width="36" height="36" viewBox="0 0 36 36" > <style> .menu-icon rect { fill: #fff; } </style> <g class="top"> <rect x="2" y="7" width="32" height="2" /> </g> <g class="middle"> <rect x="2" y="17" width="32" height="2" /> </g> <g class="bottom"> <rect x="2" y="27" width="32" height="2" /> </g> </svg> </button> <nav id="main-nav" class="mainNav" aria-hidden="true"> <ul class="navItemList list-style-none"> <li class="navItem" role="menuitem"> <a class="navLink" href="https://ag-grid.com/documentation"aria-label="AG Grid Docs">AG Grid</a> </li> <li class="navItem" role="menuitem"> <a class="navLink" href="https://charts.ag-grid.com/documentation"aria-label="AG Chart Docs">AG Charts</a> </li> <li class="navItem" role="menuitem"> <a class="navLink" href="/Newsletter" aria-label="Newsletter">Newsletter</a> </li> <li class="navItem" role="menuitem"> <a class="navLink nav-search" role="menuitem" style="cursor: pointer" data-ghost-search>Search</a> </li> <li class="navItem" role="menuitem" aria-label="AG Grid Blog"> <a class="navLink" href="/">Blog</a> </li> <li class="navItem buttonItem" role="menuitem" aria-label="AG Grid Github"> <span id="darkmode-toggle" class="navLink darkmode-toggle"> <svg class="icon moon-icon" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" ><defs><style>.cls-1{fill:none;}</style></defs><title>asleep</title><path d="M13.5025,5.4136A15.0755,15.0755,0,0,0,25.096,23.6082a11.1134,11.1134,0,0,1-7.9749,3.3893c-.1385,0-.2782.0051-.4178,0A11.0944,11.0944,0,0,1,13.5025,5.4136M14.98,3a1.0024,1.0024,0,0,0-.1746.0156A13.0959,13.0959,0,0,0,16.63,28.9973c.1641.006.3282,0,.4909,0a13.0724,13.0724,0,0,0,10.702-5.5556,1.0094,1.0094,0,0,0-.7833-1.5644A13.08,13.08,0,0,1,15.8892,4.38,1.0149,1.0149,0,0,0,14.98,3Z" /><rect id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>" class="cls-1" width="32" height="32" /></svg> <svg class="icon sun-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" ><defs><style>.cls-1{fill:none;}</style></defs><title>light</title><rect x="15" y="2" width="2" height="4.96" /><rect x="21.67" y="6.85" width="4.96" height="2" transform="translate(1.52 19.37) rotate(-45)" /><rect x="25.04" y="15" width="4.96" height="2" /><rect x="23.15" y="21.67" width="2" height="4.96" transform="translate(-10 24.15) rotate(-45)" /><rect x="15" y="25.04" width="2" height="4.96" /><rect x="5.37" y="23.15" width="4.96" height="2" transform="translate(-14.77 12.63) rotate(-45)" /><rect x="2" y="15" width="4.96" height="2" /><rect x="6.85" y="5.37" width="2" height="4.96" transform="translate(-3.25 7.85) rotate(-45)" /><path d="M16,12a4,4,0,1,1-4,4,4,4,0,0,1,4-4m0-2a6,6,0,1,0,6,6,6,6,0,0,0-6-6Z" /><rect id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>" class="cls-1" width="32" height="32" /></svg> <span>Toggle Darkmode</span> </span> </li> </ul> </nav> </div> </div> <div class="top-bar"> <div class="top-bar-inner layout-page-max-width"> <ul class="other-tags-list list-style-none"> <li> <a href="/tag/version-release/">Versions</a> </li> <li> <a href="/tag/how-to/">How toʼs</a> </li> <li> <a href="/tag/tutorial/">Tutorials</a> </li> <li> <a href="/tag/testing/">Testing</a> </li> </ul> <ul class="framework-tags-list list-style-none"> <li> <a href="/tag/javascript/"> <svg class="icon" width="100%" height="100%" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;" > <rect x="0" y="0" width="256" height="256" style="fill:rgb(247,223,30);fill-rule:nonzero;" /> <g transform="matrix(1,0,0,1,4.20544,0)"> <g transform="matrix(1,0,0,1,-27.8948,-48.7274)"> <path d="M67.312,213.932L86.903,202.076C90.682,208.777 94.12,214.447 102.367,214.447C110.272,214.447 115.256,211.355 115.256,199.327L115.256,117.529L139.314,117.529L139.314,199.667C139.314,224.584 124.708,235.926 103.398,235.926C84.153,235.926 72.982,225.959 67.311,213.93" style="fill: #000;" /> </g> <g transform="matrix(1,0,0,1,-27.8948,-48.0406)"> <path d="M152.381,211.354L171.969,200.013C177.126,208.434 183.828,214.62 195.684,214.62C205.653,214.62 212.009,209.636 212.009,202.762C212.009,194.514 205.479,191.592 194.481,186.782L188.468,184.203C171.111,176.815 159.597,167.535 159.597,147.945C159.597,129.901 173.345,116.153 194.826,116.153C210.12,116.153 221.118,121.481 229.022,135.4L210.291,147.429C206.166,140.04 201.7,137.119 194.826,137.119C187.78,137.119 183.312,141.587 183.312,147.429C183.312,154.646 187.78,157.568 198.09,162.037L204.104,164.614C224.553,173.379 236.067,182.313 236.067,202.418C236.067,224.072 219.055,235.928 196.2,235.928C173.861,235.928 159.426,225.274 152.381,211.354" style="fill: #000;" /> </g> </g> </svg> <span>Javascript</span> </a> </li> <li> <a href="/tag/react-data-grid/"> <svg class="icon" width="256px" height="228px" viewBox="0 0 256 228" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid" > <path d="M210.483381,73.8236374 C207.827698,72.9095503 205.075867,72.0446761 202.24247,71.2267368 C202.708172,69.3261098 203.135596,67.4500894 203.515631,65.6059664 C209.753843,35.3248922 205.675082,10.9302478 191.747328,2.89849283 C178.392359,-4.80289661 156.551327,3.22703567 134.492936,22.4237776 C132.371761,24.2697233 130.244662,26.2241201 128.118477,28.2723861 C126.701777,26.917204 125.287358,25.6075897 123.876584,24.3549348 C100.758745,3.82852863 77.5866802,-4.82157937 63.6725966,3.23341515 C50.3303869,10.9571328 46.3792156,33.8904224 51.9945178,62.5880206 C52.5367729,65.3599011 53.1706189,68.1905639 53.8873982,71.068617 C50.6078941,71.9995641 47.4418534,72.9920277 44.4125156,74.0478303 C17.3093297,83.497195 0,98.3066828 0,113.667995 C0,129.533287 18.5815786,145.446423 46.8116526,155.095373 C49.0394553,155.856809 51.3511025,156.576778 53.7333796,157.260293 C52.9600965,160.37302 52.2875179,163.423318 51.7229345,166.398431 C46.3687351,194.597975 50.5500231,216.989464 63.8566899,224.664425 C77.6012619,232.590464 100.66852,224.443422 123.130185,204.809231 C124.905501,203.257196 126.687196,201.611293 128.472081,199.886102 C130.785552,202.113904 133.095375,204.222319 135.392897,206.199955 C157.14963,224.922338 178.637969,232.482469 191.932332,224.786092 C205.663234,216.837268 210.125675,192.78347 204.332202,163.5181 C203.88974,161.283006 203.374826,158.99961 202.796573,156.675661 C204.416503,156.196743 206.006814,155.702335 207.557482,155.188332 C236.905331,145.46465 256,129.745175 256,113.667995 C256,98.2510906 238.132466,83.3418093 210.483381,73.8236374 L210.483381,73.8236374 Z M204.118035,144.807565 C202.718197,145.270987 201.281904,145.718918 199.818271,146.153177 C196.578411,135.896354 192.205739,124.989735 186.854729,113.72131 C191.961041,102.721277 196.164656,91.9540963 199.313837,81.7638014 C201.93261,82.5215915 204.474374,83.3208483 206.923636,84.1643056 C230.613348,92.3195488 245.063763,104.377206 245.063763,113.667995 C245.063763,123.564379 229.457753,136.411268 204.118035,144.807565 L204.118035,144.807565 Z M193.603754,165.642007 C196.165567,178.582766 196.531475,190.282717 194.834536,199.429057 C193.309843,207.64764 190.243595,213.12715 186.452366,215.321689 C178.384612,219.991462 161.131788,213.921395 142.525146,197.909832 C140.392124,196.074366 138.243609,194.114502 136.088259,192.040261 C143.301619,184.151133 150.510878,174.979732 157.54698,164.793993 C169.922699,163.695814 181.614905,161.900447 192.218042,159.449363 C192.740247,161.555956 193.204126,163.621993 193.603754,165.642007 L193.603754,165.642007 Z M87.2761866,214.514686 C79.3938934,217.298414 73.1160375,217.378157 69.3211631,215.189998 C61.2461189,210.532528 57.8891498,192.554265 62.4682434,168.438039 C62.9927272,165.676183 63.6170041,162.839142 64.3365173,159.939216 C74.8234575,162.258154 86.4299951,163.926841 98.8353334,164.932519 C105.918826,174.899534 113.336329,184.06091 120.811247,192.08264 C119.178102,193.65928 117.551336,195.16028 115.933685,196.574699 C106.001303,205.256705 96.0479605,211.41654 87.2761866,214.514686 L87.2761866,214.514686 Z M50.3486141,144.746959 C37.8658105,140.48046 27.5570398,134.935332 20.4908634,128.884403 C14.1414664,123.446815 10.9357817,118.048415 10.9357817,113.667995 C10.9357817,104.34622 24.8334611,92.4562517 48.0123604,84.3748281 C50.8247961,83.3942121 53.7689223,82.4701001 56.8242337,81.6020363 C60.0276398,92.0224477 64.229889,102.917218 69.3011135,113.93411 C64.1642716,125.11459 59.9023288,136.182975 56.6674809,146.725506 C54.489347,146.099407 52.3791089,145.440499 50.3486141,144.746959 L50.3486141,144.746959 Z M62.7270678,60.4878073 C57.9160346,35.9004118 61.1112387,17.3525532 69.1516515,12.6982729 C77.7160924,7.74005624 96.6544653,14.8094222 116.614922,32.5329619 C117.890816,33.6657739 119.171723,34.8514442 120.456275,36.0781256 C113.018267,44.0647686 105.66866,53.1573386 98.6480514,63.0655695 C86.6081646,64.1815215 75.0831931,65.9741531 64.4868907,68.3746571 C63.8206914,65.6948233 63.2305903,63.0619242 62.7270678,60.4878073 L62.7270678,60.4878073 Z M173.153901,87.7550367 C170.620796,83.3796304 168.020249,79.1076627 165.369124,74.9523483 C173.537126,75.9849113 181.362914,77.3555864 188.712066,79.0329319 C186.505679,86.1041206 183.755673,93.4974728 180.518546,101.076741 C178.196419,96.6680702 175.740322,92.2229454 173.153901,87.7550367 L173.153901,87.7550367 Z M128.122121,43.8938899 C133.166461,49.3588189 138.218091,55.4603279 143.186789,62.0803968 C138.179814,61.8439007 133.110868,61.720868 128.000001,61.720868 C122.937434,61.720868 117.905854,61.8411667 112.929865,62.0735617 C117.903575,55.515009 122.99895,49.4217021 128.122121,43.8938899 L128.122121,43.8938899 Z M82.8018984,87.830679 C80.2715265,92.2183886 77.8609975,96.6393627 75.5753239,101.068539 C72.3906004,93.5156998 69.6661103,86.0886276 67.440586,78.9171899 C74.7446255,77.2826781 82.5335049,75.9461789 90.6495601,74.9332099 C87.9610684,79.1268011 85.3391054,83.4302106 82.8018984,87.8297677 L82.8018984,87.830679 L82.8018984,87.830679 Z M90.8833221,153.182899 C82.4979621,152.247395 74.5919739,150.979704 67.289757,149.390303 C69.5508242,142.09082 72.3354636,134.505173 75.5876271,126.789657 C77.8792246,131.215644 80.2993228,135.638441 82.8451877,140.03572 L82.8456433,140.03572 C85.4388987,144.515476 88.1255676,148.90364 90.8833221,153.182899 L90.8833221,153.182899 Z M128.424691,184.213105 C123.24137,178.620587 118.071264,172.434323 113.021912,165.780078 C117.923624,165.972373 122.921029,166.0708 128.000001,166.0708 C133.217953,166.0708 138.376211,165.953235 143.45336,165.727219 C138.468257,172.501308 133.434855,178.697141 128.424691,184.213105 L128.424691,184.213105 Z M180.622896,126.396409 C184.044571,134.195313 186.929004,141.741317 189.219234,148.9164 C181.796719,150.609693 173.782736,151.973534 165.339049,152.986959 C167.996555,148.775595 170.619884,144.430263 173.197646,139.960532 C175.805484,135.438399 178.28163,130.90943 180.622896,126.396409 L180.622896,126.396409 Z M163.724586,134.496971 C159.722835,141.435557 155.614455,148.059271 151.443648,154.311611 C143.847063,154.854776 135.998946,155.134562 128.000001,155.134562 C120.033408,155.134562 112.284171,154.887129 104.822013,154.402745 C100.48306,148.068386 96.285368,141.425078 92.3091341,134.556664 L92.3100455,134.556664 C88.3442923,127.706935 84.6943232,120.799333 81.3870228,113.930466 C84.6934118,107.045648 88.3338117,100.130301 92.276781,93.292874 L92.2758697,93.294241 C96.2293193,86.4385872 100.390102,79.8276317 104.688954,73.5329157 C112.302398,72.9573964 120.109505,72.6571055 127.999545,72.6571055 L128.000001,72.6571055 C135.925583,72.6571055 143.742714,72.9596746 151.353879,73.5402067 C155.587114,79.7888993 159.719645,86.3784378 163.688588,93.2350031 C167.702644,100.168578 171.389978,107.037901 174.724618,113.77508 C171.400003,120.627999 167.720871,127.566587 163.724586,134.496971 L163.724586,134.496971 Z M186.284677,12.3729198 C194.857321,17.3165548 198.191049,37.2542268 192.804953,63.3986692 C192.461372,65.0669011 192.074504,66.7661189 191.654369,68.4881206 C181.03346,66.0374921 169.500286,64.2138746 157.425315,63.0810626 C150.391035,53.0639249 143.101577,43.9572289 135.784778,36.073113 C137.751934,34.1806885 139.716356,32.3762092 141.672575,30.673346 C160.572216,14.2257007 178.236518,7.73185406 186.284677,12.3729198 L186.284677,12.3729198 Z M128.000001,90.8080696 C140.624975,90.8080696 150.859926,101.042565 150.859926,113.667995 C150.859926,126.292969 140.624975,136.527922 128.000001,136.527922 C115.375026,136.527922 105.140075,126.292969 105.140075,113.667995 C105.140075,101.042565 115.375026,90.8080696 128.000001,90.8080696 L128.000001,90.8080696 Z" fill="#00D8FF" ></path> </svg> <span>React</span> </a> </li> <li> <a href="/tag/angular/"> <svg class="icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 223 236" width="100%" height="100%" > <g clip-path="url(#a)"> <path fill="url(#b)" d="m222.077 39.192-8.019 125.923L137.387 0l84.69 39.192Zm-53.105 162.825-57.933 33.056-57.934-33.056 11.783-28.556h92.301l11.783 28.556ZM111.039 62.675l30.357 73.803H80.681l30.358-73.803ZM7.937 165.115 0 39.192 84.69 0 7.937 165.115Z" ></path> <path fill="url(#c)" d="m222.077 39.192-8.019 125.923L137.387 0l84.69 39.192Zm-53.105 162.825-57.933 33.056-57.934-33.056 11.783-28.556h92.301l11.783 28.556ZM111.039 62.675l30.357 73.803H80.681l30.358-73.803ZM7.937 165.115 0 39.192 84.69 0 7.937 165.115Z" ></path> </g> <defs> <linearGradient id="b" x1="49.009" x2="225.829" y1="213.75" y2="129.722" gradientUnits="userSpaceOnUse" > <stop stop-color="#E40035"></stop> <stop offset=".24" stop-color="#F60A48"></stop> <stop offset=".352" stop-color="#F20755"></stop> <stop offset=".494" stop-color="#DC087D"></stop> <stop offset=".745" stop-color="#9717E7"></stop> <stop offset="1" stop-color="#6C00F5"></stop> </linearGradient> <linearGradient id="c" x1="41.025" x2="156.741" y1="28.344" y2="160.344" gradientUnits="userSpaceOnUse" > <stop stop-color="#FF31D9"></stop> <stop offset="1" stop-color="#FF5BE1" stop-opacity="0"></stop> </linearGradient> <clipPath id="a"><path fill="#fff" d="M0 0h223v236H0z" ></path></clipPath></defs></svg> <span>Angular</span> </a> </li> <li> <a href="/tag/vuejs/"> <svg class="icon" width="100%" height="100%" viewBox="0 0 256 221" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;" > <path d="M0,0L128,220.8L256,0L204.8,0L128,132.48L50.56,0L0,0Z" style="fill:rgb(65,184,131);fill-rule:nonzero;" /> <path d="M50.56,0L128,133.12L204.8,0L157.44,0L128,51.2L97.92,0L50.56,0Z" style="fill:rgb(53,73,94);fill-rule:nonzero;" /> </svg> <span>Vue</span> </a> </li> </ul> </div> </div> </div> </header> <div class="page-wrapper"> <div class="page-inner layout-grid"> <div class="side-bar"> <div> <h3>Quick Links</h3> <ul class="learn-more-list"> <li><a href="https://blog.ag-grid.com/reasons-to-choose-ag-grid-as-your-javascript-datagrid/">Why Use AG Grid?</a></li> <li><a href="https://blog.ag-grid.com/tag/tutorial/">Tutorials</a></li> <li><a href="https://blog.ag-grid.com/friends/">Friends & Collaborators</a></li> <li><a href="https://blog.ag-grid.com/showcase/">Sample Applications</a></li> </ul> <div class="side-bar-recent-posts"> <h3>Recent Posts</h3> <ul class="recent-posts-list"> <article class="content-wrap"> <li class="archive-post__title"> <a href="/whats-new-in-ag-grid-33-1/" class="archive-post"> What's New in AG Grid 33.1 </a> </li> <li class="archive-post__title"> <a href="/whats-new-in-ag-charts-11-1/" class="archive-post"> What's New in AG Charts 11.1 </a> </li> <li class="archive-post__title"> <a href="/end-to-end-testing-for-ag-grid-in-react-with-cypress/" class="archive-post"> End-to-End Testing for AG Grid in React with Cypress </a> </li> <li class="archive-post__title"> <a href="/unit-testing-ag-grid-react-tables-with-react-testing-library-and-vitest/" class="archive-post"> Unit testing AG Grid React Tables with React Testing Library and Vitest </a> </li> <li class="archive-post__title"> <a href="/introducing-our-figma-design-system-sticker-sheets/" class="archive-post"> Introducing Our Figma Design System Sticker Sheets </a> </li> <li class="archive-post__title"> <a href="/writing-e2e-tests-for-ag-grid-react-tables-with-playwright/" class="archive-post"> Writing E2E Tests for AG Grid React Tables with Playwright </a> </li> <li class="archive-post__title"> <a href="/optimizing-large-data-set-visualisations-with-the-m4-algorithm/" class="archive-post"> Optimising Large Data Set Visualisations with the M4 Algorithm </a> </li> <li class="archive-post__title"> <a href="/using-ag-grid-with-next-js-to-build-a-react-table/" class="archive-post"> Using AG Grid with Next.js to Build a React Table </a> </li> <li class="archive-post__title"> <a href="/introducing-long-term-support-for-ag-grid-and-ag-charts/" class="archive-post"> Introducing Long-Term Support (LTS) for AG Grid and AG Charts </a> </li> <li class="archive-post__title"> <a href="/upgrading-to-ag-grid-33/" class="archive-post"> Upgrading To AG Grid 33 </a> </li> </article> </ul> </div> </div> </div> <main class="main-content"> <article class="post-full post tag-react-data-grid tag-how-to tag-tutorial "> <header class="post-full-header"> <h1 class="post-full-title">Using AG Grid with Next.js to Build a React Table</h1> </header> <section class="post-full-meta"> <ul class="author-list list-style-none"> <li class="author-list-item"> <a href="/author/shadid/" class="author"> <img class="author-profile-image" src="/content/images/size/w100/2024/12/451103427_7799367756855946_4549416648696623054_n.jpg" alt="Shadid Haque" /> <span class="author-name text-secondary font-size-small">Shadid Haque</span> </a> </li> </ul> </section> <section class="post-full-meta"> <time class="post-full-meta-date text-secondary font-size-small" datetime="2025-01-07">7 January 2025</time> <span class="text-secondary font-size-small"> | </span> <a class="font-size-small" href="/tag/react-data-grid/">React</a> </section> <section class="post-full-content"> <div class="post-content"> <p>This blog shows you how to integrate AG Grid, our <a href="https://www.ag-grid.com/react-table/?ref=blog.ag-grid.com" rel="noreferrer">React Table</a> library, with <a href="https://nextjs.org/?ref=blog.ag-grid.com" rel="noreferrer">Next.js</a>:</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://blog.ag-grid.com/content/media/2024/12/Untitled-video---Made-with-Clipchamp-2_thumb.jpg" data-kg-custom-thumbnail=""> <div class="kg-video-container"> <video src="https://blog.ag-grid.com/content/media/2024/12/Untitled-video---Made-with-Clipchamp-2.mp4" poster="https://img.spacergif.org/v1/1920x1080/0a/spacer.png" width="1920" height="1080" loop="" autoplay="" muted="" playsinline="" preload="metadata" style="background: transparent url('https://blog.ag-grid.com/content/media/2024/12/Untitled-video---Made-with-Clipchamp-2_thumb.jpg') 50% 50% / cover no-repeat;"></video> <div class="kg-video-overlay"> <button class="kg-video-large-play-icon" aria-label="Play video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"></path> </svg> </button> </div> <div class="kg-video-player-container kg-video-hide"> <div class="kg-video-player"> <button class="kg-video-play-icon" aria-label="Play video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"></path> </svg> </button> <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"></rect> <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"></rect> </svg> </button> <span class="kg-video-current-time">0:00</span> <div class="kg-video-time"> /<span class="kg-video-duration">0:11</span> </div> <input type="range" class="kg-video-seek-slider" max="100" value="0"> <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1×</button> <button class="kg-video-unmute-icon" aria-label="Unmute"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"></path> </svg> </button> <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"></path> </svg> </button> <input type="range" class="kg-video-volume-slider" max="100" value="100"> </div> </div> </div> </figure><p>Check out the <a href="https://github.com/ag-grid/ag-blog-content/tree/main/grid/react/using-ag-grid-with-next-js?ref=blog.ag-grid.com" rel="noreferrer">GitHub repository</a> for the complete code or explore a live demo of the sample app on <a href="https://stackblitz.com/edit/stackblitz-starters-d6ad28ht?file=components%2FGridComponent.tsx&ref=blog.ag-grid.com" rel="noreferrer">StackBlitz</a>.</p><h2 id="content">Content</h2><ul><li><a href="#setting-up-a-nextjs-project-with-ag-grid" rel="noreferrer">Setting Up a Next.js Project with AG Grid</a></li><li><a href="#your-first-react-table" rel="noreferrer">Your First React Table</a><ul><li><a href="#client-side-rendering" rel="noreferrer">Client Side Rendering</a></li><li><a href="#ag-grid-modules" rel="noreferrer">AG Grid Modules</a></li><li><a href="#rows-and-column-definitions" rel="noreferrer">Rows and Column Definition</a></li></ul></li><li><a href="#how-to-register-the-ag-grid-enterprise-license-key" rel="noreferrer">How to Set Up a License Key for Enterprise</a></li><li><a href="#enabling-basic-features" rel="noreferrer">Enabling Basic Features</a><ul><li><a href="#filtering" rel="noreferrer">Filtering</a></li><li><a href="#editing" rel="noreferrer">Editing</a></li><li><a href="#sorting" rel="noreferrer">Sorting</a></li><li><a href="#row-selection" rel="noreferrer">Row selection</a></li><li><a href="#pagination" rel="noreferrer">Pagination</a></li></ul></li><li><a href="#integrated-charts" rel="noreferrer">Adding an Integrated Chart</a></li><li><a href="#loading-data-on-demand-with-server-side-row-model" rel="noreferrer">Loading Data on Demand with Server-Side Row Model (SSRM)</a></li></ul><h2 id="setting-up-a-nextjs-project-with-ag-grid">Setting up a Next.js project with AG Grid</h2><p>Create a new Next.js application by running the following command in your terminal:</p><pre><code class="language-sh">npx create-next-app <your-app-name></code></pre><p>When prompted, select the configuration of your preference for your Next.js application:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfGnr5_h3CmlpjC4elzFHagqMrv8X-PzrV1tYrxWVdg2SpntSL4coHhgxSXnkAIWhGZiPJMb7BcmMssPIe2wuvQ0hMrHBe5uCuQUlbWVYa_-o3AaOKvUZQ-F0j7MtwaQQ6HeuO1nQ?key=koSoIFLOMw68SnIDHsfX1SQR" class="kg-image" alt="Next.js cli prompt to create a new application" loading="lazy" width="624" height="128"></figure><p>Next, change the directory to your project folder:</p><pre><code class="language-sh">cd <your-app-name> </code></pre><p>Finally, install the <code>ag-grid-react</code> library by running the following command:</p><pre><code class="language-sh">npm i ag-grid-react --save</code></pre><p>Run your application with the <code>npm run dev</code> command and visit <a href="http://localhost:3000/?ref=blog.ag-grid.com"><u>http://localhost:3000/</u></a> to ensure everything is working as expected.</p><h2 id="your-first-react-table">Your First React Table</h2><p>To add a React Table to your application, open the <code>app/page.tsx</code> file and replace all the code in this file with the following:</p><pre><code class="language-tsx">// app/page.tsx import GridComponent from "../components/GridComponent"; export default function Home() { return ( <div > <GridComponent /> </div> ); } </code></pre><p>Next, create a new file <code>components/GridComponent.tsx</code> and add the following code:</p><pre><code class="language-tsx">// components/GridComponent.tsx "use client"; import { AgGridReact } from 'ag-grid-react'; import { useEffect, useState } from "react"; import type { ColDef } from "ag-grid-community"; import { AllCommunityModule, ModuleRegistry } from "ag-grid-community"; ModuleRegistry.registerModules([AllCommunityModule]); const GridComponent = () => { const [rowData, setRowData] = useState<any[]>([]); const [columnDefs, setColumnDefs] = useState<ColDef[]>([ { field: "athlete" }, { field: "age" }, { field: "date" }, { field: "country" }, { field: "sport" }, { field: "gold" }, { field: "silver" }, { field: "bronze" }, { field: "total" }, ]); useEffect(() => { fetch("https://www.ag-grid.com/example-assets/olympic-winners.json") // Fetch data from server .then((result) => result.json()) // Convert to JSON .then((rowData) => setRowData(rowData)); // Update state of `rowData` }, []); return ( <div style={{ width: "100%", height: "100vh" }}> <AgGridReact rowData={rowData} columnDefs={columnDefs} /> </div> ); }; export default GridComponent; </code></pre><p>You can explore the complete code for this section in the following sandbox environment:</p> <!--kg-card-begin: html--> <iframe loading="lazy" src="https://stackblitz.com/edit/stackblitz-starters-lmptktcb?ctl=1&embed=1&file=components%2FGridComponent.tsx&hideNavigation=1" style="width:100%; height:600px; border:0; border-radius: 4px; overflow:hidden; margin: 10px 0 25px !important" width="100%" height="600px" ></iframe> <!--kg-card-end: html--> <p>Let’s break down the code in the <code>GridComponent.tsx</code> file...</p><h3 id="client-side-rendering">Client Side Rendering</h3><p>We created a <a href="https://nextjs.org/docs/pages/building-your-application/rendering/client-side-rendering?ref=blog.ag-grid.com"><u>client-rendered</u></a> component because the <code>ag-grid-react</code> library depends on some browser-specific APIs (e.g., <code>window</code> / <code>document</code>) and can not be rendered server-side. The <code>use client</code> keyword at the top of the file tells Next.js that this component will be rendered on the client side (browser) and not server-side.</p><h3 id="ag-grid-modules">AG Grid Modules</h3><p><a href="https://www.ag-grid.com/react-data-grid/modules/?ref=blog.ag-grid.com" rel="noreferrer">AG Grid Modules</a> allow you to reduce your application bundle size by cherry-picking grid features. </p><p>When you register a module with the <code>ModuleRegistry</code> it becomes available globally to all instances of AG Grid in your application. For example, to access the <a href="https://www.ag-grid.com/react-data-grid/csv-export/?ref=blog.ag-grid.com" rel="noreferrer">CSV Export</a> feature in AG Grid, you need to import & register the <code>CsvExportModule</code>:</p><pre><code class="language-tsx">import { ClientSideRowModelModule, CsvExportModule, ModuleRegistry } from 'ag-grid-community'; // Register specific modules ModuleRegistry.registerModules([ClientSideRowModelModule, CsvExportModule]); </code></pre><p>There is a handy <a href="https://www.ag-grid.com/react-data-grid/modules/?ref=blog.ag-grid.com#selecting-modules" rel="noreferrer">module selector</a> that can help you pick up the relevant modules for your application. </p><p>If bundle size is not a concern, you can register <code>AllCommunityModule</code> to access all the Community features available within AG Grid, which we're using for this example.</p><h3 id="rows-and-column-definitions">Rows and Column Definitions </h3><p><a href="https://www.ag-grid.com/react-data-grid/column-definitions/?ref=blog.ag-grid.com" rel="noreferrer">Column Definitions</a> define the structure and configuration of the columns in the AG Grid table. They specify how data is displayed, formatted, and interacted with for each column in the grid.</p><p>The <code>columnDefs</code> state variable in the code is an array of objects, where each object represents the configuration for a single column.</p><pre><code class="language-tsx">const [columnDefs, setColumnDefs] = useState<ColDef[]>([ { field: 'athlete' }, { field: 'age' }, { field: 'date' }, { field: 'country' }, { field: 'sport' }, { field: 'gold' }, { field: 'silver' }, { field: 'bronze' }, { field: 'total' }, ]);</code></pre><p><a href="https://www.ag-grid.com/react-data-grid/row-ids/?ref=blog.ag-grid.com" rel="noreferrer">Rows</a> represent the individual records displayed in the <a href="https://www.ag-grid.com/react-table?ref=blog.ag-grid.com" rel="noreferrer">React Table</a>. These rows are populated using the data stored in the <code>rowData</code> state variable, which is fetched from an external source:</p><pre><code class="language-tsx">const [rowData, setRowData] = useState<any[]>([]); useEffect(() => { fetch("https://www.ag-grid.com/example-assets/olympic-winners.json") .then(result => result.json()) // Convert to JSON .then(rowData => setRowData(rowData)); // Update state of `rowData` }, []);</code></pre><p>Finally, we render the AG Grid component with the <code>rowData</code> and <code>columnDefs</code> props:</p><pre><code class="language-tsx">return ( <div style={{ width: '100%', height: '100vh' }}> <AgGridReact rowData={rowData} columnDefs={columnDefs} /> </div> );</code></pre><p>Note that we are setting a <code>height</code> property on the container. <code>AgGridReact</code> component needs a container with explicit dimensions to properly render its layout. If the height of the container is not defined, the grid may not render correctly.</p><p>Open your application on <a href="http://localhost:3000/?ref=blog.ag-grid.com">http://localhost:3000/</a> and make sure that the table is working as expected - you should see something like this:</p><figure class="kg-card kg-image-card"><img src="https://blog.ag-grid.com/content/images/2024/12/new.png" class="kg-image" alt="React data table rendered in browser" loading="lazy" width="1919" height="1079" srcset="https://blog.ag-grid.com/content/images/size/w600/2024/12/new.png 600w, https://blog.ag-grid.com/content/images/size/w1000/2024/12/new.png 1000w, https://blog.ag-grid.com/content/images/size/w1600/2024/12/new.png 1600w, https://blog.ag-grid.com/content/images/2024/12/new.png 1919w" sizes="(min-width: 720px) 720px"></figure><h2 id="enabling-basic-features">Enabling Basic Features</h2><p>AG Grid's <a href="https://www.ag-grid.com/react-table?ref=blog.ag-grid.com" rel="noreferrer">React Table</a> library offers a wide array of features to facilitate the display and manipulation of tabular data. Some key features of AG Grid include <a href="https://www.ag-grid.com/react-data-grid/grouping-sorting/?ref=blog.ag-grid.com" rel="noreferrer">sorting</a>, <a href="https://www.ag-grid.com/react-data-grid/aggregation-filtering/?ref=blog.ag-grid.com" rel="noreferrer">filtering</a>, <a href="https://www.ag-grid.com/react-data-grid/server-side-model-pagination/?ref=blog.ag-grid.com" rel="noreferrer">pagination</a>, <a href="https://www.ag-grid.com/react-data-grid/row-selection/?ref=blog.ag-grid.com" rel="noreferrer">row selection</a>, and <a href="https://www.ag-grid.com/react-data-grid/cell-editors/?ref=blog.ag-grid.com" rel="noreferrer">cell editing</a>.</p><p>These features can be enabled on specific columns by adding the relevant property in the column object in the column definitions array or you can use <code>defaultColDef</code> property to apply these configurations to all columns.</p><p>The <code>defaultColDef</code> property allows you to specify default configurations for all columns in your grid. For instance, if you want all the columns to be resizable unless specified otherwise, you can do so by setting <code>sortable: true</code> in the <code>defaultColDef</code> property.</p><p>In the following code block, all columns except the date column are resizable:</p><pre><code class="language-tsx">const [columnDefs, setColumnDefs] = useState<ColDef[]>([ { field: 'athlete' }, { field: 'age' }, { field: 'date', resizable: false }, // Don't allow resizing { field: 'country' }, { field: 'sport' }, { field: 'gold' }, { field: 'silver' }, { field: 'bronze' }, { field: 'total' }, ]); const [defaultColDef, setDefaultColDef] = useState({ resizable: true, }); return ( <div style={{ width: '100%', height: '100vh' }}> <AgGridReact rowData={rowData} columnDefs={columnDefs} defaultColDef={defaultColDef} /> </div> );</code></pre><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://blog.ag-grid.com/content/media/2024/12/Untitled-video---Made-with-Clipchamp--1--1_thumb.jpg" data-kg-custom-thumbnail=""> <div class="kg-video-container"> <video src="https://blog.ag-grid.com/content/media/2024/12/Untitled-video---Made-with-Clipchamp--1--1.mp4" poster="https://img.spacergif.org/v1/1920x1080/0a/spacer.png" width="1920" height="1080" loop="" autoplay="" muted="" playsinline="" preload="metadata" style="background: transparent url('https://blog.ag-grid.com/content/media/2024/12/Untitled-video---Made-with-Clipchamp--1--1_thumb.jpg') 50% 50% / cover no-repeat;"></video> <div class="kg-video-overlay"> <button class="kg-video-large-play-icon" aria-label="Play video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"></path> </svg> </button> </div> <div class="kg-video-player-container kg-video-hide"> <div class="kg-video-player"> <button class="kg-video-play-icon" aria-label="Play video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"></path> </svg> </button> <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"></rect> <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"></rect> </svg> </button> <span class="kg-video-current-time">0:00</span> <div class="kg-video-time"> /<span class="kg-video-duration">0:05</span> </div> <input type="range" class="kg-video-seek-slider" max="100" value="0"> <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1×</button> <button class="kg-video-unmute-icon" aria-label="Unmute"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"></path> </svg> </button> <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"></path> </svg> </button> <input type="range" class="kg-video-volume-slider" max="100" value="100"> </div> </div> </div> </figure><h3 id="filtering">Filtering</h3><p>Column <a href="https://www.ag-grid.com/react-data-grid/filtering-overview/?ref=blog.ag-grid.com" rel="noreferrer">filters</a> are enabled via the filter attribute. You can specify a <a href="https://www.ag-grid.com/react-data-grid/filtering/?ref=blog.ag-grid.com#column-filter-types" rel="noreferrer">filter data type</a>, or set filter to true and the type will be inferred based on cell data. You can also create floating filters by setting the <code>floatingFilter</code> attribute. The floating filter displays the column filter directly in the header for quick access: </p><pre><code class="language-tsx">const [columnDefs, setColumnDefs] = useState<ColDef[]>([ { field: 'athlete', filter: 'agTextColumnFilter' }, { field: 'age', filter: true }, { field: 'date', resizable: false, filter: 'agDateColumnFilter' }, { field: 'country' }, { field: 'sport' }, { field: 'gold' }, { field: 'silver' }, { field: 'bronze' }, { field: 'total' }, ]);</code></pre><p>In the previous code block we applied the <em>text filter</em> to the <code>athlete</code> column and the <em>date filter</em> to date column. We also set <code>filter: true</code> for the age column and AG Grid automatically <a href="https://www.ag-grid.com/react-data-grid/cell-data-types/?ref=blog.ag-grid.com#inferring-data-types" rel="noreferrer">infers a <em>number filter</em></a>. </p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://blog.ag-grid.com/content/media/2024/12/filter_thumb.jpg" data-kg-custom-thumbnail=""> <div class="kg-video-container"> <video src="https://blog.ag-grid.com/content/media/2024/12/filter.mp4" poster="https://img.spacergif.org/v1/1920x1080/0a/spacer.png" width="1920" height="1080" loop="" autoplay="" muted="" playsinline="" preload="metadata" style="background: transparent url('https://blog.ag-grid.com/content/media/2024/12/filter_thumb.jpg') 50% 50% / cover no-repeat;"></video> <div class="kg-video-overlay"> <button class="kg-video-large-play-icon" aria-label="Play video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"></path> </svg> </button> </div> <div class="kg-video-player-container kg-video-hide"> <div class="kg-video-player"> <button class="kg-video-play-icon" aria-label="Play video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"></path> </svg> </button> <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"></rect> <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"></rect> </svg> </button> <span class="kg-video-current-time">0:00</span> <div class="kg-video-time"> /<span class="kg-video-duration">0:08</span> </div> <input type="range" class="kg-video-seek-slider" max="100" value="0"> <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1×</button> <button class="kg-video-unmute-icon" aria-label="Unmute"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"></path> </svg> </button> <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"></path> </svg> </button> <input type="range" class="kg-video-volume-slider" max="100" value="100"> </div> </div> </div> </figure><p>You can also set any of these filters in the <code>defaultColDef</code> to apply them to all columns.</p><h3 id="editing">Editing</h3><p>To enable Cell Editing for a Column use the editable property on the Column Definition.</p><pre><code class="language-tsx">const [columnDefs, setColumnDefs] = useState<ColDef[]>([ { field: 'athlete', filter: 'agTextColumnFilter', editable: true, onCellValueChanged: (event) => { console.log(event.data); // Handle the cell value change event // Here, you can update the data in the server or perform any other action } }, // ... rest of the column objects ]);</code></pre><p>The <code>onCellValueChanged</code> function runs after the cell value is updated. You can use this function to make API calls to update the data in the server or perform other actions as needed.</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://blog.ag-grid.com/content/media/2024/12/edit_thumb.jpg" data-kg-custom-thumbnail=""> <div class="kg-video-container"> <video src="https://blog.ag-grid.com/content/media/2024/12/edit.mp4" poster="https://img.spacergif.org/v1/1920x1080/0a/spacer.png" width="1920" height="1080" loop="" autoplay="" muted="" playsinline="" preload="metadata" style="background: transparent url('https://blog.ag-grid.com/content/media/2024/12/edit_thumb.jpg') 50% 50% / cover no-repeat;"></video> <div class="kg-video-overlay"> <button class="kg-video-large-play-icon" aria-label="Play video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"></path> </svg> </button> </div> <div class="kg-video-player-container kg-video-hide"> <div class="kg-video-player"> <button class="kg-video-play-icon" aria-label="Play video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"></path> </svg> </button> <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"></rect> <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"></rect> </svg> </button> <span class="kg-video-current-time">0:00</span> <div class="kg-video-time"> /<span class="kg-video-duration">0:07</span> </div> <input type="range" class="kg-video-seek-slider" max="100" value="0"> <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1×</button> <button class="kg-video-unmute-icon" aria-label="Unmute"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"></path> </svg> </button> <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"></path> </svg> </button> <input type="range" class="kg-video-volume-slider" max="100" value="100"> </div> </div> </div> </figure><p></p><h3 id="sorting">Sorting</h3><p>Sorting is enabled by default. You can click on the column names to sort by ascending or descending order. You can also sort by multiple columns. Hold shift and select the columns that you want to sort by. </p><p>If you want to disable sorting for a particular column you can specify it in the column definition. For instance, if I want to disable sorting in the country column I can do so by setting <code>sortable: false</code>.</p><pre><code class="language-tsx">const [columnDefs, setColumnDefs] = useState<ColDef[]>([ // ... Rest of the columns { field: 'country', sortable: false }, ]);</code></pre><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://blog.ag-grid.com/content/media/2024/12/sorting_thumb.jpg" data-kg-custom-thumbnail=""> <div class="kg-video-container"> <video src="https://blog.ag-grid.com/content/media/2024/12/sorting.mp4" poster="https://img.spacergif.org/v1/1920x1080/0a/spacer.png" width="1920" height="1080" loop="" autoplay="" muted="" playsinline="" preload="metadata" style="background: transparent url('https://blog.ag-grid.com/content/media/2024/12/sorting_thumb.jpg') 50% 50% / cover no-repeat;"></video> <div class="kg-video-overlay"> <button class="kg-video-large-play-icon" aria-label="Play video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"></path> </svg> </button> </div> <div class="kg-video-player-container kg-video-hide"> <div class="kg-video-player"> <button class="kg-video-play-icon" aria-label="Play video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"></path> </svg> </button> <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"></rect> <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"></rect> </svg> </button> <span class="kg-video-current-time">0:00</span> <div class="kg-video-time"> /<span class="kg-video-duration">0:08</span> </div> <input type="range" class="kg-video-seek-slider" max="100" value="0"> <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1×</button> <button class="kg-video-unmute-icon" aria-label="Unmute"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"></path> </svg> </button> <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"></path> </svg> </button> <input type="range" class="kg-video-volume-slider" max="100" value="100"> </div> </div> </div> </figure><h3 id="row-selection">Row Selection</h3><p>You can select rows by passing the <code>rowSelection</code> props in the <code>AgGridReact</code> component.</p><pre><code class="language-tsx">const rowSelection = useMemo(() => { return { mode: 'singleRow', }; }, []); return ( <div style={{ width: '100%', height: '100vh' }}> <AgGridReact rowData={rowData} columnDefs={columnDefs} defaultColDef={defaultColDef} rowSelection={rowSelection as RowSelectionOptions} /> </div> );</code></pre><p>In the <code>mode</code> you can select <code>singleRow</code> option to enable only one row selection at a time or select <code>multiRow</code> option for selecting multiple row. Learn more about <a href="https://www.ag-grid.com/react-data-grid/row-selection/?ref=blog.ag-grid.com" rel="noreferrer">row selection here</a>.</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://blog.ag-grid.com/content/media/2024/12/row_selection_thumb.jpg" data-kg-custom-thumbnail=""> <div class="kg-video-container"> <video src="https://blog.ag-grid.com/content/media/2024/12/row_selection.mp4" poster="https://img.spacergif.org/v1/1920x1080/0a/spacer.png" width="1920" height="1080" loop="" autoplay="" muted="" playsinline="" preload="metadata" style="background: transparent url('https://blog.ag-grid.com/content/media/2024/12/row_selection_thumb.jpg') 50% 50% / cover no-repeat;"></video> <div class="kg-video-overlay"> <button class="kg-video-large-play-icon" aria-label="Play video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"></path> </svg> </button> </div> <div class="kg-video-player-container kg-video-hide"> <div class="kg-video-player"> <button class="kg-video-play-icon" aria-label="Play video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"></path> </svg> </button> <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"></rect> <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"></rect> </svg> </button> <span class="kg-video-current-time">0:00</span> <div class="kg-video-time"> /<span class="kg-video-duration">0:04</span> </div> <input type="range" class="kg-video-seek-slider" max="100" value="0"> <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1×</button> <button class="kg-video-unmute-icon" aria-label="Unmute"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"></path> </svg> </button> <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"></path> </svg> </button> <input type="range" class="kg-video-volume-slider" max="100" value="100"> </div> </div> </div> </figure><h3 id="pagination">Pagination</h3><p>You can add <a href="https://www.ag-grid.com/archive/33.0.0/react-data-grid/server-side-model-pagination/?ref=blog.ag-grid.com#enabling-pagination" rel="noreferrer">pagination </a>by setting the pagination options.</p><pre><code class="language-tsx">const pagination = useMemo(() => { return { pagination: true, paginationPageSize: 10, paginationPageSizeSelector: [10, 20, 30, 40, 50], }; }, []); return ( <div style={{ width: '100%', height: '100vh' }}> <AgGridReact rowData={rowData} columnDefs={columnDefs} defaultColDef={defaultColDef} rowSelection={rowSelection as RowSelectionOptions} pagination={pagination} /> </div> );</code></pre><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://blog.ag-grid.com/content/media/2024/12/pagination_thumb.jpg" data-kg-custom-thumbnail=""> <div class="kg-video-container"> <video src="https://blog.ag-grid.com/content/media/2024/12/pagination.mp4" poster="https://img.spacergif.org/v1/1920x1080/0a/spacer.png" width="1920" height="1080" loop="" autoplay="" muted="" playsinline="" preload="metadata" style="background: transparent url('https://blog.ag-grid.com/content/media/2024/12/pagination_thumb.jpg') 50% 50% / cover no-repeat;"></video> <div class="kg-video-overlay"> <button class="kg-video-large-play-icon" aria-label="Play video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"></path> </svg> </button> </div> <div class="kg-video-player-container kg-video-hide"> <div class="kg-video-player"> <button class="kg-video-play-icon" aria-label="Play video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"></path> </svg> </button> <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"></rect> <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"></rect> </svg> </button> <span class="kg-video-current-time">0:00</span> <div class="kg-video-time"> /<span class="kg-video-duration">0:08</span> </div> <input type="range" class="kg-video-seek-slider" max="100" value="0"> <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1×</button> <button class="kg-video-unmute-icon" aria-label="Unmute"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"></path> </svg> </button> <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"></path> </svg> </button> <input type="range" class="kg-video-volume-slider" max="100" value="100"> </div> </div> </div> </figure><h2 id="how-to-register-the-ag-grid-enterprise-license-key">How to Register the AG Grid Enterprise License Key</h2><p>To access the Enterprise features of AG Grid in production, you need to register your license key. </p><p>Given that AG Grid runs on the browser, the license key has to be exposed on the client side of the Next.js application. First, create a new variable in your <code>.env</code> file for the license key:</p><pre><code class="language-sh"># .env NEXT_PUBLIC_AG_GRID_LICENSE="your_license_key"</code></pre><p>In Next.js all environment variables by default are accessible only within the Node.js environment. Prefixing the name of an environment variable with <code>NEXT_PUBLIC_</code> makes it <a href="https://nextjs.org/docs/app/building-your-application/configuring/environment-variables?ref=blog.ag-grid.com#bundling-environment-variables-for-the-browser" rel="noreferrer">available on the client side</a>. </p><p>Next, install the ag-grid-enterprise library:</p><pre><code class="language-sh">npm i ag-grid-enterprise --save</code></pre><p>Finally, add the following code to your <code>GridComponent.tsx</code> file to import the LicenseManager and set your license key:</p><pre><code class="language-tsx">import 'ag-grid-enterprise'; // Import the Enterprise features import { LicenseManager } from "ag-grid-enterprise"; // Register License Key with LicenseManager LicenseManager.setLicenseKey(process.env.NEXT_PUBLIC_AG_GRID_LICENSE || '');</code></pre><p>To ensure your key is properly set up, check that your app does not display a watermark or a console warning in the browser.</p><p>You can choose to trial any enterprise features at any time by installing the <code>ag-grid-enterprise</code> and <code>ag-charts-enterprise</code> packages. The only restrictions are:</p><ul><ul><li>You will get a watermark in your charts and react tables when using the free version</li><li>You will get errors in your browser console stating that a license key is needed to use this feature</li></ul></ul><p>To avoid this, you can request a trial license key by emailing us at <a href="mailto:info@ag-grid.com" rel="noreferrer">info@ag-grid.com</a></p><h2 id="integrated-charts">Integrated charts</h2><p>Next, let's add an <a href="https://www.ag-grid.com/react-data-grid/integrated-charts/?ref=blog.ag-grid.com" rel="noreferrer">Integrated Chart</a> to our <a href="https://www.ag-grid.com/react-table?ref=blog.ag-grid.com" rel="noreferrer">React Table</a> to allow users to visualize data directly within the grid interface</p><p>Integrated Charts is an enterprise feature of AG Grid, meaning you need to install the <code>ag-grid-enterprise</code> package to access it. There are also two versions of Integrated Charts: Community & Enterprise. Purchasing a license key for AG Grid provides access to Community Integrated Charts. To access all of the Enterprise Features of AG Charts, you'll also need an AG Charts Enterprise licence. </p><p>For this example, we'll focus on AG Charts Enterprise. To install it, run the following command:</p><pre><code class="language-sh ">npm i ag-charts-enterprise --save</code></pre><p>Next, import the <code>IntegratedChartsModule</code> and <code>AgChartsEnterpriseModule</code>.</p><pre><code class="language-tsx">import { AgGridReact } from 'ag-grid-react'; import { IntegratedChartsModule, ContextMenuModule } from 'ag-grid-enterprise'; import { AgChartsEnterpriseModule } from 'ag-charts-enterprise'; ModuleRegistry.registerModules([ AllCommunityModule, ContextMenuModule, IntegratedChartsModule.with(AgChartsEnterpriseModule), ]);</code></pre><p>By calling <code>IntegratedChartsModule.with(AgChartsEnterpriseModule)</code> inside your module registry, you are telling AG Grid to enable charting features in your data table.</p><p>The <code>ContextMenuModule</code> is also required to enable the right-click context menu, which we'll use to build the charts within the grid. </p><p>Finally, add the <code>enableCharts</code> and <code>rowSelection</code> props to your <code>AgGridReact</code> component:</p><pre><code class="language-tsx">const rowSelection = useMemo(() => { return { mode: 'multiRow', }; }, []); <div style={{ width: '100%', height: '100vh' }}> <AgGridReact rowData={rowData} columnDefs={columnDefs} defaultColDef={defaultColDef} enableCharts // Enable the Charting features cellSelection rowSelection={rowSelection as RowSelectionOptions} /> </div></code></pre><p>You can select multiple rows at once by dragging your mouse or holding <code>ctrl</code>. Once you select multiple rows, right-click and you will get a chart option to create a chart from the selected data.</p><p>The following is the complete code example for creating an Integrated Chart:</p> <!--kg-card-begin: html--> <iframe loading="lazy" src="https://stackblitz.com/edit/stackblitz-starters-9jgkjrgf?ctl=1&embed=1&file=components%2FGridComponent.tsx&hideExplorer=1&hideNavigation=1&view=editor" style="width:100%; height:600px; border:0; border-radius: 4px; overflow:hidden; margin: 10px 0 25px !important" width="100%" height="600px" ></iframe> <!--kg-card-end: html--> <figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://blog.ag-grid.com/content/media/2024/12/integrated_2_thumb.jpg" data-kg-custom-thumbnail=""> <div class="kg-video-container"> <video src="https://blog.ag-grid.com/content/media/2024/12/integrated_2.mp4" poster="https://img.spacergif.org/v1/1920x1080/0a/spacer.png" width="1920" height="1080" loop="" autoplay="" muted="" playsinline="" preload="metadata" style="background: transparent url('https://blog.ag-grid.com/content/media/2024/12/integrated_2_thumb.jpg') 50% 50% / cover no-repeat;"></video> <div class="kg-video-overlay"> <button class="kg-video-large-play-icon" aria-label="Play video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"></path> </svg> </button> </div> <div class="kg-video-player-container kg-video-hide"> <div class="kg-video-player"> <button class="kg-video-play-icon" aria-label="Play video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"></path> </svg> </button> <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"></rect> <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"></rect> </svg> </button> <span class="kg-video-current-time">0:00</span> <div class="kg-video-time"> /<span class="kg-video-duration">0:08</span> </div> <input type="range" class="kg-video-seek-slider" max="100" value="0"> <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1×</button> <button class="kg-video-unmute-icon" aria-label="Unmute"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"></path> </svg> </button> <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"></path> </svg> </button> <input type="range" class="kg-video-volume-slider" max="100" value="100"> </div> </div> </div> </figure><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">💡</div><div class="kg-callout-text">AG Grid incorporates <a href="https://www.ag-grid.com/charts/?ref=blog.ag-grid.com" rel="noreferrer">AG Charts</a> to provide integrated charting capabilities. AG Charts is a comprehensive <a href="https://www.ag-grid.com/charts?ref=blog.ag-grid.com" rel="noreferrer">JavaScript Charting Library</a> designed to create interactive and customizable charts, which can also be used as a standalone charting library. </div></div><h2 id="loading-data-on-demand-with-server-side-row-model">Loading Data on Demand with Server-Side Row Model</h2><p>AG Grid's <a href="https://www.ag-grid.com/react-data-grid/server-side-model/?ref=blog.ag-grid.com" rel="noreferrer">Server-Side Row Model (SSRM)</a> is designed to efficiently handle large datasets by loading data on-demand from the server rather than fetching the data all at once in the browser. This approach reduces the browser's memory footprint and improves performance. </p><p>The <a href="https://www.ag-grid.com/javascript-data-grid/server-side-model/?utm_source=chatgpt.com#features" rel="noreferrer">key features</a> of SSRM are:</p><ul><li><strong>Lazy-Loading of Groups:</strong> Initially, only top-level rows are loaded. Child rows within groups are fetched from the server when the user expands the respective group.</li><li><strong>Infinite Scrolling:</strong> Data is retrieved in blocks; as the user scrolls through more data is loaded from the server side in chunks.</li><li><strong>Server-Side Operations:</strong> Operations such as sorting, filtering, grouping, and aggregation are executed on the server for larger datasets.</li></ul><h3 id="implement-server-side-sorting">Implement Server-Side Sorting</h3><p>Let's demonstrate this by implementing Server-Side Sorting using SSRM. </p><p>First, in your <code>GridComponent</code> import and register the <code>ServerSideRowModelModule</code>:</p><pre><code class="language-tsx">import { ContextMenuModule, IntegratedChartsModule, ServerSideRowModelModule, // import SSRM module } from 'ag-grid-enterprise'; ModuleRegistry.registerModules([ AllCommunityModule, ContextMenuModule, ServerSideRowModelModule, // register SSRM IntegratedChartsModule.with(AgChartsEnterpriseModule), ]);</code></pre><p>The actual sorting of rows is performed on the server when using the Server-Side Row Model. One main component of this model is the <a href="https://www.ag-grid.com/react-data-grid/server-side-model-datasource/?ref=blog.ag-grid.com">Server-Side Datasource</a>, which acts as a bridge between the grid and your server, facilitating data retrieval based on user interactions.</p><p>Write a new function, <code>getServerSideDatasource</code>, that creates a Server-Side Data source. AG Grid will use this function to fetch data on demand:</p><pre><code class="language-tsx">const getServerSideDatasource = (): IServerSideDatasource => { return { async getRows(params: IServerSideGetRowsParams) { console.log('[Datasource] - rows requested by grid: ', params.request); try { const response = await fetch('/api/mock-server', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params.request as IServerSideGetRowsRequest), }); if (!response.ok) { console.error('Failed to fetch data from server'); params.fail(); return; } const data = await response.json(); console.log('[Datasource] - rows returned from server: ', data); if (data.success) { params.success({ rowData: data.rows, rowCount: data.lastRow, }); } else { params.fail(); } } catch (error) { console.error('Error fetching data: ', error); params.fail(); } }, }; }; </code></pre><p>Let's break down the code above...</p><p>The function returns an object containing the <code>getRows</code> method, which AG Grid invokes when it requires data:</p><pre><code class="language-tsx">return { async getRows(params: IServerSideGetRowsParams) { // ... }, };</code></pre><p>The <code>params</code> object provides details about the request, including sorting, filtering, and the range of rows needed.</p><p>Inside the <code>getRows</code> function it sends a POST request to the server endpoint <code>/api/mock-server</code>.</p><pre><code class="language-tsx">const response = await fetch('/api/mock-server', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params.request as IServerSideGetRowsRequest), }); </code></pre><p>If the server indicates success, it calls <code>params.success()</code> with the retrieved rows and the total row count. Otherwise, it calls <code>params.fail()</code>:</p><pre><code class="language-tsx">if (data.success) { params.success({ rowData: data.rows, rowCount: data.lastRow, }); } else { params.fail(); } </code></pre><p>The <code>params.success()</code> call delivers the retrieved data back to the grid.</p><p>In your <code>AgGridReact</code> component add the <code>rowModelType={'serverSide'}</code> option to enable the Server-Side Row Model:</p><pre><code class="language-tsx"><AgGridReact columnDefs={columnDefs} defaultColDef={defaultColDef} enableCharts={true} // Enable the Charting features cellSelection={true} rowSelection={{ mode: 'multiRow', }} rowModelType={'serverSide'} // enables SSRM onGridReady={onGridReady} // /></code></pre><p>In the <code>AgGridReact</code> component there is an <a href="https://www.ag-grid.com/react-data-grid/grid-lifecycle/?ref=blog.ag-grid.com" rel="noreferrer"><code>onGridReady</code></a> prop, which accepts a callback function that executes when the grid has completed initializing:</p><pre><code class="language-tsx">const onGridReady = useCallback((params: GridReadyEvent) => { console.log('Grid ready event received'); const datasource = getServerSideDatasource(); // Register the datasource with the grid params.api!.setGridOption('serverSideDatasource', datasource as any); }, []);</code></pre><p>Inside the callback function, we call the <code>getServerSideDatasource</code> function to get the data from the server and then the grid consumes the returned data.</p><p>For this to work we need an API endpoint that takes care of the sorting logic on the server. We can implement a mock endpoint using a Next.js <a href="https://nextjs.org/docs/app/building-your-application/routing?ref=blog.ag-grid.com#the-app-router" rel="noreferrer">app router API route.</a> </p><p>Create a new file <code>app/api/mock-server/route.ts</code> and add the following code:</p><pre><code class="language-ts">// app/api/mock-server/route.ts import { NextRequest, NextResponse } from 'next/server'; interface SortModel { colId: string; sort: 'asc' | 'desc'; } interface IServerSideGetRowsRequest { startRow: number; endRow: number; sortModel?: SortModel[]; } export async function POST(request: NextRequest) { const reqBody = (await request.json()) as IServerSideGetRowsRequest; // Fetch data from the external API const dataResponse = await fetch( 'https://www.ag-grid.com/example-assets/olympic-winners.json' ); const olympicData = (await dataResponse.json()) as any[]; let rows = [...olympicData]; // Sorting logic if (reqBody.sortModel && reqBody.sortModel.length > 0) { rows.sort((a, b) => { for (const sortDef of reqBody.sortModel!) { const { colId, sort } = sortDef; const aValue = a[colId]; const bValue = b[colId]; if (aValue < bValue) return sort === 'asc' ? -1 : 1; if (aValue > bValue) return sort === 'asc' ? 1 : -1; } return 0; }); } const { startRow = 0, endRow = rows.length } = reqBody; const requestedRows = rows.slice(startRow, endRow); const lastRow = rows.length; return NextResponse.json({ success: true, rows: requestedRows, lastRow: lastRow, }); } </code></pre><p>The provided code defines a POST API route in a Next.js application that serves as a mock server for AG Grid's Server-Side Row Model. It processes data requests from the grid, applies server-side sorting based on the grid's specifications, and returns the appropriate subset of data.</p><p>If the request includes a <code>sortModel</code>, the function sorts the data accordingly. It iterates through the sorting instructions, comparing values of the specified columns and ordering the rows based on the specified sort direction (<code>asc</code> for ascending or <code>desc</code> for descending).</p><pre><code class="language-ts">if (reqBody.sortModel && reqBody.sortModel.length > 0) { rows.sort((a, b) => { for (const sortDef of reqBody.sortModel!) { const { colId, sort } = sortDef; const aValue = a[colId]; const bValue = b[colId]; if (aValue < bValue) return sort === 'asc' ? -1 : 1; if (aValue > bValue) return sort === 'asc' ? 1 : -1; } return 0; }); }</code></pre><p>You can find the complete code example for this section in the following sandbox environment:</p> <!--kg-card-begin: html--> <iframe loading="lazy" src="https://stackblitz.com/edit/stackblitz-starters-d6ad28ht?ctl=1&embed=1&file=components%2FGridComponent.tsx&hideExplorer=1&hideNavigation=1" style="width:100%; height:600px; border:0; border-radius: 4px; overflow:hidden; margin: 10px 0 25px !important" width="100%" height="600px" ></iframe> <!--kg-card-end: html--> <p>You can find a more in-depth explanation of the <a href="https://www.ag-grid.com/react-data-grid/server-side-model/?ref=blog.ag-grid.com"><u>Server Side Row Model (SSRM) in our docs.</u></a></p><h2 id="where-to-go-from-here">Where to go from here</h2><p>In this article, you learned how to implement AG Grid in Next.js. To learn more about AG Grid visit <a href="https://www.ag-grid.com/react-data-grid/getting-started/?ref=blog.ag-grid.com" rel="noreferrer">our Documentation</a>.</p><p>You can also find plenty of real-world examples, open-source projects and code samples on our <a href="https://www.ag-grid.com/community/?ref=blog.ag-grid.com" rel="noreferrer">Community Page</a>.</p> </div> </section> <footer class="share-footer"> <span class="share-label text-secondary">Share</span> <a class="share-social-media twitter" href="https://twitter.com/share?text=Using AG Grid with Next.js to Build a React Table&url=https://blog.ag-grid.com/using-ag-grid-with-next-js-to-build-a-react-table/" onclick="window.open(this.href, 'twitter-share', 'width=550,height=235');return false;" title="Twitter" target="_blank" rel="noopener"><svg width="1092" height="1075" viewBox="0 0 1092 1075" fill="none" xmlns="http://www.w3.org/2000/svg" size="32" class="icon" ><g clip-path="url(#clip0_404_5)"><path d="M622.109 475.189L919.927 129H849.353L590.758 429.591L384.219 129H146L458.328 583.547L146 946.58H216.577L489.661 629.145L707.781 946.58H946L622.091 475.189H622.109ZM525.443 587.552L493.798 542.289L242.007 182.13H350.41L553.608 472.79L585.253 518.053L849.387 895.867H740.984L525.443 587.569V587.552Z" ></path></g><defs><clipPath id="clip0_404_5"><rect width="800" height="818" transform="translate(146 129)" ></rect></clipPath></defs></svg></a> <a class="share-social-media facebook" href="https://www.facebook.com/sharer/sharer.php?u=https://blog.ag-grid.com/using-ag-grid-with-next-js-to-build-a-react-table/" onclick="window.open(this.href, 'facebook-share','width=580,height=296');return false;" title="Facebook" target="_blank" rel="noopener"><svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M19 6h5V0h-5c-3.86 0-7 3.14-7 7v3H8v6h4v16h6V16h5l1-6h-6V7c0-.542.458-1 1-1z" /></svg></a> </footer> <footer class="post-full-footer"> <ul class="author-list author-list-large list-style-none"> <li class="author-list-item"> <a href="/author/shadid/" class="author"> <img class="author-profile-image" src="/content/images/size/w100/2024/12/451103427_7799367756855946_4549416648696623054_n.jpg" alt="Shadid Haque" /> <span class="author-name text-secondary font-size-extra-large">Shadid Haque</span> </a> </li> </ul> </footer> <p class="tags-list-description text-secondary font-size-medium">Read more posts about...</p> <ul class="other-tags-list list-style-none"> <li> <a href="/tag/version-release/">Versions</a> </li> <li> <a href="/tag/how-to/">How toʼs</a> </li> <li> <a href="/tag/tutorial/">Tutorials</a> </li> <li> <a href="/tag/testing/">Testing</a> </li> </ul> <ul class="framework-tags-list list-style-none"> <li> <a href="/tag/javascript/"> <svg class="icon" width="100%" height="100%" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;" > <rect x="0" y="0" width="256" height="256" style="fill:rgb(247,223,30);fill-rule:nonzero;" /> <g transform="matrix(1,0,0,1,4.20544,0)"> <g transform="matrix(1,0,0,1,-27.8948,-48.7274)"> <path d="M67.312,213.932L86.903,202.076C90.682,208.777 94.12,214.447 102.367,214.447C110.272,214.447 115.256,211.355 115.256,199.327L115.256,117.529L139.314,117.529L139.314,199.667C139.314,224.584 124.708,235.926 103.398,235.926C84.153,235.926 72.982,225.959 67.311,213.93" style="fill: #000;" /> </g> <g transform="matrix(1,0,0,1,-27.8948,-48.0406)"> <path d="M152.381,211.354L171.969,200.013C177.126,208.434 183.828,214.62 195.684,214.62C205.653,214.62 212.009,209.636 212.009,202.762C212.009,194.514 205.479,191.592 194.481,186.782L188.468,184.203C171.111,176.815 159.597,167.535 159.597,147.945C159.597,129.901 173.345,116.153 194.826,116.153C210.12,116.153 221.118,121.481 229.022,135.4L210.291,147.429C206.166,140.04 201.7,137.119 194.826,137.119C187.78,137.119 183.312,141.587 183.312,147.429C183.312,154.646 187.78,157.568 198.09,162.037L204.104,164.614C224.553,173.379 236.067,182.313 236.067,202.418C236.067,224.072 219.055,235.928 196.2,235.928C173.861,235.928 159.426,225.274 152.381,211.354" style="fill: #000;" /> </g> </g> </svg> <span>Javascript</span> </a> </li> <li> <a href="/tag/react-data-grid/"> <svg class="icon" width="256px" height="228px" viewBox="0 0 256 228" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid" > <path d="M210.483381,73.8236374 C207.827698,72.9095503 205.075867,72.0446761 202.24247,71.2267368 C202.708172,69.3261098 203.135596,67.4500894 203.515631,65.6059664 C209.753843,35.3248922 205.675082,10.9302478 191.747328,2.89849283 C178.392359,-4.80289661 156.551327,3.22703567 134.492936,22.4237776 C132.371761,24.2697233 130.244662,26.2241201 128.118477,28.2723861 C126.701777,26.917204 125.287358,25.6075897 123.876584,24.3549348 C100.758745,3.82852863 77.5866802,-4.82157937 63.6725966,3.23341515 C50.3303869,10.9571328 46.3792156,33.8904224 51.9945178,62.5880206 C52.5367729,65.3599011 53.1706189,68.1905639 53.8873982,71.068617 C50.6078941,71.9995641 47.4418534,72.9920277 44.4125156,74.0478303 C17.3093297,83.497195 0,98.3066828 0,113.667995 C0,129.533287 18.5815786,145.446423 46.8116526,155.095373 C49.0394553,155.856809 51.3511025,156.576778 53.7333796,157.260293 C52.9600965,160.37302 52.2875179,163.423318 51.7229345,166.398431 C46.3687351,194.597975 50.5500231,216.989464 63.8566899,224.664425 C77.6012619,232.590464 100.66852,224.443422 123.130185,204.809231 C124.905501,203.257196 126.687196,201.611293 128.472081,199.886102 C130.785552,202.113904 133.095375,204.222319 135.392897,206.199955 C157.14963,224.922338 178.637969,232.482469 191.932332,224.786092 C205.663234,216.837268 210.125675,192.78347 204.332202,163.5181 C203.88974,161.283006 203.374826,158.99961 202.796573,156.675661 C204.416503,156.196743 206.006814,155.702335 207.557482,155.188332 C236.905331,145.46465 256,129.745175 256,113.667995 C256,98.2510906 238.132466,83.3418093 210.483381,73.8236374 L210.483381,73.8236374 Z M204.118035,144.807565 C202.718197,145.270987 201.281904,145.718918 199.818271,146.153177 C196.578411,135.896354 192.205739,124.989735 186.854729,113.72131 C191.961041,102.721277 196.164656,91.9540963 199.313837,81.7638014 C201.93261,82.5215915 204.474374,83.3208483 206.923636,84.1643056 C230.613348,92.3195488 245.063763,104.377206 245.063763,113.667995 C245.063763,123.564379 229.457753,136.411268 204.118035,144.807565 L204.118035,144.807565 Z M193.603754,165.642007 C196.165567,178.582766 196.531475,190.282717 194.834536,199.429057 C193.309843,207.64764 190.243595,213.12715 186.452366,215.321689 C178.384612,219.991462 161.131788,213.921395 142.525146,197.909832 C140.392124,196.074366 138.243609,194.114502 136.088259,192.040261 C143.301619,184.151133 150.510878,174.979732 157.54698,164.793993 C169.922699,163.695814 181.614905,161.900447 192.218042,159.449363 C192.740247,161.555956 193.204126,163.621993 193.603754,165.642007 L193.603754,165.642007 Z M87.2761866,214.514686 C79.3938934,217.298414 73.1160375,217.378157 69.3211631,215.189998 C61.2461189,210.532528 57.8891498,192.554265 62.4682434,168.438039 C62.9927272,165.676183 63.6170041,162.839142 64.3365173,159.939216 C74.8234575,162.258154 86.4299951,163.926841 98.8353334,164.932519 C105.918826,174.899534 113.336329,184.06091 120.811247,192.08264 C119.178102,193.65928 117.551336,195.16028 115.933685,196.574699 C106.001303,205.256705 96.0479605,211.41654 87.2761866,214.514686 L87.2761866,214.514686 Z M50.3486141,144.746959 C37.8658105,140.48046 27.5570398,134.935332 20.4908634,128.884403 C14.1414664,123.446815 10.9357817,118.048415 10.9357817,113.667995 C10.9357817,104.34622 24.8334611,92.4562517 48.0123604,84.3748281 C50.8247961,83.3942121 53.7689223,82.4701001 56.8242337,81.6020363 C60.0276398,92.0224477 64.229889,102.917218 69.3011135,113.93411 C64.1642716,125.11459 59.9023288,136.182975 56.6674809,146.725506 C54.489347,146.099407 52.3791089,145.440499 50.3486141,144.746959 L50.3486141,144.746959 Z M62.7270678,60.4878073 C57.9160346,35.9004118 61.1112387,17.3525532 69.1516515,12.6982729 C77.7160924,7.74005624 96.6544653,14.8094222 116.614922,32.5329619 C117.890816,33.6657739 119.171723,34.8514442 120.456275,36.0781256 C113.018267,44.0647686 105.66866,53.1573386 98.6480514,63.0655695 C86.6081646,64.1815215 75.0831931,65.9741531 64.4868907,68.3746571 C63.8206914,65.6948233 63.2305903,63.0619242 62.7270678,60.4878073 L62.7270678,60.4878073 Z M173.153901,87.7550367 C170.620796,83.3796304 168.020249,79.1076627 165.369124,74.9523483 C173.537126,75.9849113 181.362914,77.3555864 188.712066,79.0329319 C186.505679,86.1041206 183.755673,93.4974728 180.518546,101.076741 C178.196419,96.6680702 175.740322,92.2229454 173.153901,87.7550367 L173.153901,87.7550367 Z M128.122121,43.8938899 C133.166461,49.3588189 138.218091,55.4603279 143.186789,62.0803968 C138.179814,61.8439007 133.110868,61.720868 128.000001,61.720868 C122.937434,61.720868 117.905854,61.8411667 112.929865,62.0735617 C117.903575,55.515009 122.99895,49.4217021 128.122121,43.8938899 L128.122121,43.8938899 Z M82.8018984,87.830679 C80.2715265,92.2183886 77.8609975,96.6393627 75.5753239,101.068539 C72.3906004,93.5156998 69.6661103,86.0886276 67.440586,78.9171899 C74.7446255,77.2826781 82.5335049,75.9461789 90.6495601,74.9332099 C87.9610684,79.1268011 85.3391054,83.4302106 82.8018984,87.8297677 L82.8018984,87.830679 L82.8018984,87.830679 Z M90.8833221,153.182899 C82.4979621,152.247395 74.5919739,150.979704 67.289757,149.390303 C69.5508242,142.09082 72.3354636,134.505173 75.5876271,126.789657 C77.8792246,131.215644 80.2993228,135.638441 82.8451877,140.03572 L82.8456433,140.03572 C85.4388987,144.515476 88.1255676,148.90364 90.8833221,153.182899 L90.8833221,153.182899 Z M128.424691,184.213105 C123.24137,178.620587 118.071264,172.434323 113.021912,165.780078 C117.923624,165.972373 122.921029,166.0708 128.000001,166.0708 C133.217953,166.0708 138.376211,165.953235 143.45336,165.727219 C138.468257,172.501308 133.434855,178.697141 128.424691,184.213105 L128.424691,184.213105 Z M180.622896,126.396409 C184.044571,134.195313 186.929004,141.741317 189.219234,148.9164 C181.796719,150.609693 173.782736,151.973534 165.339049,152.986959 C167.996555,148.775595 170.619884,144.430263 173.197646,139.960532 C175.805484,135.438399 178.28163,130.90943 180.622896,126.396409 L180.622896,126.396409 Z M163.724586,134.496971 C159.722835,141.435557 155.614455,148.059271 151.443648,154.311611 C143.847063,154.854776 135.998946,155.134562 128.000001,155.134562 C120.033408,155.134562 112.284171,154.887129 104.822013,154.402745 C100.48306,148.068386 96.285368,141.425078 92.3091341,134.556664 L92.3100455,134.556664 C88.3442923,127.706935 84.6943232,120.799333 81.3870228,113.930466 C84.6934118,107.045648 88.3338117,100.130301 92.276781,93.292874 L92.2758697,93.294241 C96.2293193,86.4385872 100.390102,79.8276317 104.688954,73.5329157 C112.302398,72.9573964 120.109505,72.6571055 127.999545,72.6571055 L128.000001,72.6571055 C135.925583,72.6571055 143.742714,72.9596746 151.353879,73.5402067 C155.587114,79.7888993 159.719645,86.3784378 163.688588,93.2350031 C167.702644,100.168578 171.389978,107.037901 174.724618,113.77508 C171.400003,120.627999 167.720871,127.566587 163.724586,134.496971 L163.724586,134.496971 Z M186.284677,12.3729198 C194.857321,17.3165548 198.191049,37.2542268 192.804953,63.3986692 C192.461372,65.0669011 192.074504,66.7661189 191.654369,68.4881206 C181.03346,66.0374921 169.500286,64.2138746 157.425315,63.0810626 C150.391035,53.0639249 143.101577,43.9572289 135.784778,36.073113 C137.751934,34.1806885 139.716356,32.3762092 141.672575,30.673346 C160.572216,14.2257007 178.236518,7.73185406 186.284677,12.3729198 L186.284677,12.3729198 Z M128.000001,90.8080696 C140.624975,90.8080696 150.859926,101.042565 150.859926,113.667995 C150.859926,126.292969 140.624975,136.527922 128.000001,136.527922 C115.375026,136.527922 105.140075,126.292969 105.140075,113.667995 C105.140075,101.042565 115.375026,90.8080696 128.000001,90.8080696 L128.000001,90.8080696 Z" fill="#00D8FF" ></path> </svg> <span>React</span> </a> </li> <li> <a href="/tag/angular/"> <svg class="icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 223 236" width="100%" height="100%" > <g clip-path="url(#a)"> <path fill="url(#b)" d="m222.077 39.192-8.019 125.923L137.387 0l84.69 39.192Zm-53.105 162.825-57.933 33.056-57.934-33.056 11.783-28.556h92.301l11.783 28.556ZM111.039 62.675l30.357 73.803H80.681l30.358-73.803ZM7.937 165.115 0 39.192 84.69 0 7.937 165.115Z" ></path> <path fill="url(#c)" d="m222.077 39.192-8.019 125.923L137.387 0l84.69 39.192Zm-53.105 162.825-57.933 33.056-57.934-33.056 11.783-28.556h92.301l11.783 28.556ZM111.039 62.675l30.357 73.803H80.681l30.358-73.803ZM7.937 165.115 0 39.192 84.69 0 7.937 165.115Z" ></path> </g> <defs> <linearGradient id="b" x1="49.009" x2="225.829" y1="213.75" y2="129.722" gradientUnits="userSpaceOnUse" > <stop stop-color="#E40035"></stop> <stop offset=".24" stop-color="#F60A48"></stop> <stop offset=".352" stop-color="#F20755"></stop> <stop offset=".494" stop-color="#DC087D"></stop> <stop offset=".745" stop-color="#9717E7"></stop> <stop offset="1" stop-color="#6C00F5"></stop> </linearGradient> <linearGradient id="c" x1="41.025" x2="156.741" y1="28.344" y2="160.344" gradientUnits="userSpaceOnUse" > <stop stop-color="#FF31D9"></stop> <stop offset="1" stop-color="#FF5BE1" stop-opacity="0"></stop> </linearGradient> <clipPath id="a"><path fill="#fff" d="M0 0h223v236H0z" ></path></clipPath></defs></svg> <span>Angular</span> </a> </li> <li> <a href="/tag/vuejs/"> <svg class="icon" width="100%" height="100%" viewBox="0 0 256 221" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;" > <path d="M0,0L128,220.8L256,0L204.8,0L128,132.48L50.56,0L0,0Z" style="fill:rgb(65,184,131);fill-rule:nonzero;" /> <path d="M50.56,0L128,133.12L204.8,0L157.44,0L128,51.2L97.92,0L50.56,0Z" style="fill:rgb(53,73,94);fill-rule:nonzero;" /> </svg> <span>Vue</span> </a> </li> </ul> <script type="text/javascript" src="//s3.amazonaws.com/downloads.mailchimp.com/js/mc-validate.js" ></script> <script type="text/javascript">(function($) {window.fnames = new Array(); window.ftypes = new Array();fnames[0]='EMAIL';ftypes[0]='email';fnames[1]='FNAME';ftypes[1]='text';fnames[3]='ADDRESS';ftypes[3]='address';fnames[4]='PHONE';ftypes[4]='phone';}(jQuery));var $mcj = jQuery.noConflict(true);</script> <div id="mc_embed_signup" style="width: 100%;"> <form action="https://ag-grid.us11.list-manage.com/subscribe/post?u=9b44b788c97fa5b498fbbc9b5&id=9353cf87ce" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate > <div id="mc_embed_signup_scroll"> <label class="text-secondary font-size-small">Join the AG Grid Newsletter</label> <input type="email" value="" name="EMAIL" class="required email" id="mce-EMAIL" placeholder="email" /> <input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe" class="button button-secondary" /> <div id="mce-responses" class="clear"> <div class="response" id="mce-error-response" style="display:none" ></div> <div class="response" id="mce-success-response" style="display:none" ></div> </div> <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--> <div style="position: absolute; left: -5000px;" aria-hidden="true"> <input type="text" name="b_9b44b788c97fa5b498fbbc9b5_9353cf87ce" tabindex="-1" value="" /> </div> </div> </form> </div> </article> </main> <aside class="read-next-outer"> <div class="read-next-inner"> <article class="read-next-card" > <header class="read-next-card-header"> <small class="read-next-card-header-sitetitle">— AG Grid Blog —</small> <h3 class="read-next-card-header-title"><a href="/tag/react-data-grid/">React</a></h3> </header> <div class="read-next-divider"><svg class="icon infinity-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" > <style> .infinity-icon { fill: transparent; stroke-width: 1px; } </style> <path d="M13 14.5s2 3 5 3 5.5-2.463 5.5-5.5S21 6.5 18 6.5c-5 0-7 11-12 11C2.962 17.5.5 15.037.5 12S3 6.5 6 6.5s4.5 3.5 4.5 3.5" /></svg></div> <div class="read-next-card-content"> <ul class="list-style-none"> <li><a href="/end-to-end-testing-for-ag-grid-in-react-with-cypress/">End-to-End Testing for AG Grid in React with Cypress</a></li> <li><a href="/unit-testing-ag-grid-react-tables-with-react-testing-library-and-vitest/">Unit testing AG Grid React Tables with React Testing Library and Vitest</a></li> <li><a href="/writing-e2e-tests-for-ag-grid-react-tables-with-playwright/">Writing E2E Tests for AG Grid React Tables with Playwright</a></li> </ul> </div> <footer class="read-next-card-footer"> <a href="/tag/react-data-grid/">See all 57 posts →</a> </footer> </article> <article class="post-card post "> <a class="post-card-image-link" href="/optimizing-large-data-set-visualisations-with-the-m4-algorithm/"> <img class="post-card-image" srcset="/content/images/size/w300/2024/11/Optimising-JavaScript-Charts-with-the-M4-Algorithm.png 300w, /content/images/size/w600/2024/11/Optimising-JavaScript-Charts-with-the-M4-Algorithm.png 600w, /content/images/size/w1000/2024/11/Optimising-JavaScript-Charts-with-the-M4-Algorithm.png 1000w, /content/images/size/w2000/2024/11/Optimising-JavaScript-Charts-with-the-M4-Algorithm.png 2000w" sizes="(max-width: 1000px) 400px, 700px" src="/content/images/size/w600/2024/11/Optimising-JavaScript-Charts-with-the-M4-Algorithm.png" alt="Optimising Large Data Set Visualisations with the M4 Algorithm" /> </a> <div class="post-card-content"> <a class="post-card-content-link" href="/optimizing-large-data-set-visualisations-with-the-m4-algorithm/"> <header class="post-card-header"> <h2 class="post-card-title">Optimising Large Data Set Visualisations with the M4 Algorithm</h2> </header> <section class="post-card-excerpt"> <p>A deep dive into how we implemented the M4 algorithm to create a line chart that can support over a million data points and maintain 60fps during interactivity.</p> </section> </a> <footer class="post-card-meta"> <ul class="author-list list-style-none"> <li class="author-list-item"> <a href="/author/james/" class="author"> <img class="author-profile-image" src="/content/images/size/w100/2024/08/me.jpeg" alt="James Swinton-Bland" /> <span class="author-name text-secondary font-size-small">James Swinton-Bland</span> </a> </li> </ul> <span class="reading-time text-secondary font-size-small">5 min read</span> </footer> </div> </article> <article class="post-card post tag-version-release "> <a class="post-card-image-link" href="/introducing-long-term-support-for-ag-grid-and-ag-charts/"> <img class="post-card-image" srcset="/content/images/size/w300/2024/12/Introducing-Long-Term-Support-for-AG-Grid-and-AG-Charts-1.png 300w, /content/images/size/w600/2024/12/Introducing-Long-Term-Support-for-AG-Grid-and-AG-Charts-1.png 600w, /content/images/size/w1000/2024/12/Introducing-Long-Term-Support-for-AG-Grid-and-AG-Charts-1.png 1000w, /content/images/size/w2000/2024/12/Introducing-Long-Term-Support-for-AG-Grid-and-AG-Charts-1.png 2000w" sizes="(max-width: 1000px) 400px, 700px" src="/content/images/size/w600/2024/12/Introducing-Long-Term-Support-for-AG-Grid-and-AG-Charts-1.png" alt="Introducing Long-Term Support (LTS) for AG Grid and AG Charts" /> </a> <div class="post-card-content"> <span class="post-card-tag text-secondary">Releases</span> <a class="post-card-content-link" href="/introducing-long-term-support-for-ag-grid-and-ag-charts/"> <header class="post-card-header"> <h2 class="post-card-title">Introducing Long-Term Support (LTS) for AG Grid and AG Charts</h2> </header> <section class="post-card-excerpt"> <p>To help those who need more time to upgrade, we're now offering Long-Term Support (LTS) versions of AG Grid (v32-lts) and AG Charts (v10-lts).</p> </section> </a> <footer class="post-card-meta"> <ul class="author-list list-style-none"> <li class="author-list-item"> <a href="/author/james/" class="author"> <img class="author-profile-image" src="/content/images/size/w100/2024/08/me.jpeg" alt="James Swinton-Bland" /> <span class="author-name text-secondary font-size-small">James Swinton-Bland</span> </a> </li> </ul> <span class="reading-time text-secondary font-size-small">3 min read</span> </footer> </div> </article> </div> </aside> </div> </div> <!-- closed --> <footer class="site-footer"> <div class="darkmode-data-target"> <div class="footer"> <div class="footerColumns layout-grid"> <div class="menuColumn"> <h4 class="thin-text">Documentation</h4> <ul class="list-style-none"> <li><a href="https://www.ag-grid.com/javascript-grid/getting-started/" >Getting Started</a></li> <li><a href="https://www.ag-grid.com/ag-grid-changelog/" >Changelog</a></li> <li><a href="https://www.ag-grid.com/ag-grid-pipeline/" >Pipeline</a></li> <li><a href="https://www.ag-grid.com/archive/">Documentation Archive</a></li> </ul> </div> <div class="menuColumn"> <h4 class="thin-text">Support & Community</h4> <ul class="list-style-none"> <li><a href="https://stackoverflow.com/questions/tagged/ag-grid">Stack Overflow</a></li> <li><a href="https://www.ag-grid.com/license-pricing.php">License & Pricing</a></li> <li><a href="https://ag-grid.zendesk.com/">Support via Zendesk</a></li> </ul> </div> <div class="menuColumn"> <h4 class="thin-text">The Company</h4> <ul class="list-style-none"> <li><a href="https://www.ag-grid.com/about.php">About</a></li> <li><a href="https://blog.ag-grid.com/">Blog</a></li> <li><a href="https://www.ag-grid.com/privacy.php">Privacy Policy</a></li> <li><a href="https://www.ag-grid.com/cookies.php">Cookies Policy</a></li> </ul> </div> <div class="menuColumn"> <h4 class="thin-text">Follow</h4> <ul class="list-style-none"> <li><a href="https://github.com/ag-grid/ag-grid" target="_blank" rel="noopener" > <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M16,2a14,14,0,0,0-4.43,27.28c.7.13,1-.3,1-.67s0-1.21,0-2.38c-3.89.84-4.71-1.88-4.71-1.88A3.71,3.71,0,0,0,6.24,22.3c-1.27-.86.1-.85.1-.85A2.94,2.94,0,0,1,8.48,22.9a3,3,0,0,0,4.08,1.16,2.93,2.93,0,0,1,.88-1.87c-3.1-.36-6.37-1.56-6.37-6.92a5.4,5.4,0,0,1,1.44-3.76,5,5,0,0,1,.14-3.7s1.17-.38,3.85,1.43a13.3,13.3,0,0,1,7,0c2.67-1.81,3.84-1.43,3.84-1.43a5,5,0,0,1,.14,3.7,5.4,5.4,0,0,1,1.44,3.76c0,5.38-3.27,6.56-6.39,6.91a3.33,3.33,0,0,1,.95,2.59c0,1.87,0,3.38,0,3.84s.25.81,1,.67A14,14,0,0,0,16,2Z" /></svg> Github </a></li> <li><a href="https://twitter.com/ag_grid" target="_blank" rel="noopener" > <svg width="1092" height="1075" viewBox="0 0 1092 1075" fill="none" xmlns="http://www.w3.org/2000/svg" size="32" class="icon" ><g clip-path="url(#clip0_404_5)"><path d="M622.109 475.189L919.927 129H849.353L590.758 429.591L384.219 129H146L458.328 583.547L146 946.58H216.577L489.661 629.145L707.781 946.58H946L622.091 475.189H622.109ZM525.443 587.552L493.798 542.289L242.007 182.13H350.41L553.608 472.79L585.253 518.053L849.387 895.867H740.984L525.443 587.569V587.552Z" ></path></g><defs><clipPath id="clip0_404_5"><rect width="800" height="818" transform="translate(146 129)" ></rect></clipPath></defs></svg> X </a></li> <li><a href="https://youtube.com/c/ag-grid" target="_blank" rel="noopener" > <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M29.41,9.26a3.5,3.5,0,0,0-2.47-2.47C24.76,6.2,16,6.2,16,6.2s-8.76,0-10.94.59A3.5,3.5,0,0,0,2.59,9.26,36.13,36.13,0,0,0,2,16a36.13,36.13,0,0,0,.59,6.74,3.5,3.5,0,0,0,2.47,2.47C7.24,25.8,16,25.8,16,25.8s8.76,0,10.94-.59a3.5,3.5,0,0,0,2.47-2.47A36.13,36.13,0,0,0,30,16,36.13,36.13,0,0,0,29.41,9.26ZM13.2,20.2V11.8L20.47,16Z" /></svg> YouTube </a></li> <li><a href="https://www.linkedin.com/company/ag-grid" target="_blank" rel="noopener" > <svg version="1.1" class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="32px" height="32px" viewBox="0 0 32 32" style="enable-background:new 0 0 32 32;" xml:space="preserve" > <path d="M26.2,4H5.8C4.8,4,4,4.8,4,5.7v20.5c0,0.9,0.8,1.7,1.8,1.7h20.4c1,0,1.8-0.8,1.8-1.7V5.7C28,4.8,27.2,4,26.2,4z M11.1,24.4 H7.6V13h3.5V24.4z M9.4,11.4c-1.1,0-2.1-0.9-2.1-2.1c0-1.2,0.9-2.1,2.1-2.1c1.1,0,2.1,0.9,2.1,2.1S10.5,11.4,9.4,11.4z M24.5,24.3 H21v-5.6c0-1.3,0-3.1-1.9-3.1c-1.9,0-2.1,1.5-2.1,2.9v5.7h-3.5V13h3.3v1.5h0.1c0.5-0.9,1.7-1.9,3.4-1.9c3.6,0,4.3,2.4,4.3,5.5V24.3z " /> </svg> LinkedIn </a></li> </ul> </div> </div> <div class="layout-grid"> <p className="text-sm thin-text"> AG Grid Ltd registered in the United Kingdom. Company No. 07318192. </p> <p className="text-sm thin-text">© AG Grid Ltd. 2015-2025</p> </div> </div> </div> </footer> <script> window.addEventListener('load', (event) => { var images = document.querySelectorAll('.kg-gallery-image img'); images.forEach(function (image) { var container = image.closest('.kg-gallery-image'); var width = image.attributes.width.value; var height = image.attributes.height.value; var ratio = width / height; container.style.flex = ratio + ' 1 0%'; }) }); </script> <script> const toggleMobileMenu = () => { const button = document.querySelector('.mobileMenuButton'); const nav = document.querySelector('#main-nav'); button.ariaExpanded = button.ariaExpanded === 'true' ? false : true; nav.ariaHidden = nav.ariaHidden === 'true' ? false : true; }; </script> <script> const postTitle = document.querySelector('.post-full-title'); if (postTitle) { const wordArr = postTitle.innerHTML.split(' '); let orphanless = ""; wordArr.forEach((word, i) => { orphanless += i !== wordArr.length - 1 ? ` ${word}` : ` ${word}`; }); postTitle.innerHTML = orphanless; } </script> </body> </html>