<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Infinite Table</title>
    <description>The latest articles on DEV Community by Infinite Table (@get_infinite).</description>
    <link>https://dev.to/get_infinite</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F844882%2Fc14a099e-9737-43fd-af8e-aac6bae5ead9.png</url>
      <title>DEV Community: Infinite Table</title>
      <link>https://dev.to/get_infinite</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/get_infinite"/>
    <language>en</language>
    <item>
      <title>Infinite Table React DataGrid version 3.0.0 released</title>
      <dc:creator>Infinite Table</dc:creator>
      <pubDate>Wed, 04 Oct 2023 21:42:20 +0000</pubDate>
      <link>https://dev.to/get_infinite/infinite-table-react-datagrid-version-300-released-5ea6</link>
      <guid>https://dev.to/get_infinite/infinite-table-react-datagrid-version-300-released-5ea6</guid>
      <description>&lt;p&gt;Version &lt;code&gt;3.0.0&lt;/code&gt; is a release that brings a long awaited feature: cell selection. This allows the user to perform fined-grained cell selection, either via the &lt;a href="https://infinite-table.com/docs/reference/datasource-props#cellSelection"&gt;cellSelection&lt;/a&gt; prop or via the &lt;a href="https://infinite-table.com/docs/reference/cell-selection-api"&gt;Cell Selection API&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Version 3.0.0 highlights 🎉
&lt;/h1&gt;

&lt;p&gt;1️⃣ support for single and multiple cell selection&lt;br&gt;
  2️⃣ cell selection using wildcards&lt;br&gt;
  3️⃣ cell selection API&lt;/p&gt;
&lt;h2&gt;
  
  
  1️⃣ Support for single and multiple cell selection
&lt;/h2&gt;

&lt;p&gt;It's been a &lt;a href="https://github.com/infinite-table/infinite-react/issues/120"&gt;long-requested feature to implement cell selection&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We knew we needed to implement it, but we wanted to do it right while keeping it easy to understand.&lt;/p&gt;

&lt;p&gt;In fact, we prepared some things in advance - namely &lt;a href="https://infinite-table.com/docs/reference/datasource-props#selectionMode"&gt;selectionMode&lt;/a&gt; was there, it just needed to accept a new value: &lt;code&gt;"multi-cell"&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataSource&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="na"&gt;Developer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  selectionMode="multi-cell" // &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;---&lt;/span&gt; &lt;span class="na"&gt;THIS&lt;/span&gt;
  &lt;span class="na"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[...]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The line above is all you need to do to enable cell selection. This allows the user to &lt;code&gt;Click&lt;/code&gt; or &lt;code&gt;Cmd/Ctrl+Click&lt;/code&gt; to select a specific cell and &lt;code&gt;Shift+Click&lt;/code&gt; to select a range of cells. It's exactly the behavior you'd expect from a spreadsheet application.&lt;/p&gt;

&lt;p&gt;Try &lt;code&gt;Cmd/Ctrl+Click&lt;/code&gt;ing in the DataGrid cells below to see multiple cell selection in action.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/cell-selection-with-infinite-table-qnvwwh"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Using a default selection
&lt;/h3&gt;

&lt;p&gt;If you want to render the DataGrid with a default selection, you can use the &lt;a href="https://infinite-table.com/docs/reference/datasource-props#defaultCellSelection"&gt;defaultCellSelection&lt;/a&gt; prop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaultCellSelection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;defaultSelection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;selectedCells&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hobby&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hobby&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preferredLanguage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;salary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The format for the uncontrolled &lt;a href="https://infinite-table.com/docs/reference/datasource-props#defaultCellSelection"&gt;defaultCellSelection&lt;/a&gt; (and also for the controlled &lt;a href="https://infinite-table.com/docs/reference/datasource-props#cellSelection"&gt;cellSelection&lt;/a&gt;) is an object with two properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;defaultSelection&lt;/code&gt; - &lt;code&gt;boolean&lt;/code&gt; - whether or not cells are selected by default.&lt;/li&gt;
&lt;li&gt;and either

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;selectedCells&lt;/code&gt; - &lt;code&gt;[string|number, string][]&lt;/code&gt; - only needed when &lt;code&gt;defaultSelection&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;or

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;deselectedCells&lt;/code&gt; - &lt;code&gt;[string|number, string][]&lt;/code&gt; - only needed when &lt;code&gt;defaultSelection&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The value for &lt;code&gt;selectedCells&lt;/code&gt; and &lt;code&gt;deselectedCells&lt;/code&gt; should be an array of &lt;code&gt;[rowId, colId]&lt;/code&gt; tuples.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;rowId&lt;/code&gt; is the &lt;code&gt;id&lt;/code&gt; of the row (&lt;a href="https://infinite-table.com/docs/reference/datasource-props#primaryKey"&gt;primaryKey&lt;/a&gt;), and the &lt;code&gt;colId&lt;/code&gt; is the &lt;code&gt;id&lt;/code&gt; of the column (the identifier of the column in the  prop).&lt;/p&gt;

&lt;p&gt;This object shape for the &lt;a href="https://infinite-table.com/docs/reference/datasource-props#defaultCellSelection"&gt;defaultCellSelection&lt;/a&gt;/&lt;a href="https://infinite-table.com/docs/reference/datasource-props#cellSelection"&gt;cellSelection&lt;/a&gt; props allows you full flexibility in specifying the selection. You can specify a single cell, a range of cells, or even a non-contiguous selection. You can default to everything being selected, or everything being deselected and then enumerate your specific exceptions.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/cell-selection-with-default-value-in-infinite-table-fzdhwr"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  2️⃣ Cell Selection using wildcards
&lt;/h2&gt;

&lt;p&gt;The above examples show how to select specific cells, but what if you want to select all cells in a column, or all cells in a row?&lt;/p&gt;

&lt;p&gt;Well, that turns out to be straightforward as well. You can use the &lt;code&gt;*&lt;/code&gt; wildcard to select all cells in a column or all cells in a row.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// All cells in row with id rowId3&lt;/span&gt;
&lt;span class="c1"&gt;// and all cells in hobby column are selected&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaultCellSelection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;defaultSelection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;selectedCells&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hobby&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rowId3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataSource&lt;/span&gt; 
  &lt;span class="na"&gt;selectionMode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"multi-cell"&lt;/span&gt;
  &lt;span class="na"&gt;defaultCellSelection&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;defaultCellSelection&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wildcard selection is really powerful and it allows you to select lots of cells without the need to enumerate them all.&lt;/p&gt;

&lt;p&gt;For example, you can easily select all cells except a few.&lt;/p&gt;

&lt;h3&gt;
  
  
  Listening to selection changes
&lt;/h3&gt;

&lt;p&gt;You can listen to selection changes by using the &lt;a href="https://infinite-table.com/docs/reference/datasource-props#onCellSelectionChange"&gt;onCellSelectionChange&lt;/a&gt; prop.&lt;/p&gt;

&lt;p&gt;If you're using controlled cell selection, you have to update the &lt;a href="https://infinite-table.com/docs/reference/datasource-props#cellSelection"&gt;cellSelection&lt;/a&gt; prop yourself in response to user interaction - so &lt;a href="https://infinite-table.com/docs/reference/datasource-props#onCellSelectionChange"&gt;onCellSelectionChange&lt;/a&gt; will be your way of listening to selection changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  3️⃣ Cell Selection API
&lt;/h2&gt;

&lt;p&gt;In addition to managing cell selection declaratively, which we encourage, you can also use the &lt;a href="https://dev.to/docs/reference/cell-selection-api"&gt;Cell Selection API&lt;/a&gt; to imperatively update the current selection.&lt;/p&gt;

&lt;p&gt;We offer the following methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/reference/cell-selection-api#selectCell"&gt;selectCell&lt;/a&gt; - selects a single cell, while allowing you to keep or to clear previous selection&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/reference/cell-selection-api#deselectCell"&gt;deselectCell&lt;/a&gt; - deselects the specified cell&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/reference/cell-selection-api#selectColumn"&gt;selectColumn&lt;/a&gt; - selects a whole column in the DataGrid&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/reference/cell-selection-api#deselectColumn"&gt;deselectColumn&lt;/a&gt; - deselects the specified column&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/reference/cell-selection-api#selectRange"&gt;selectRange&lt;/a&gt; - selects a range of cells&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/reference/cell-selection-api#deselectRange"&gt;deselectRange&lt;/a&gt; - deselects the specified range of cells&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/reference/cell-selection-api#selectAll"&gt;selectAll&lt;/a&gt; - selects all cells in the DataGrid&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/reference/cell-selection-api#clear"&gt;clear&lt;/a&gt; - clears selection (deselects all cells in the DataGrid)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/reference/cell-selection-api#isCellSelected"&gt;isCellSelected&lt;/a&gt; - checks if the specified cell is selected or not&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;We'd love to hear your feedback - what do you think we've got right and what's missing. Please reach out to us via email at &lt;a href="mailto:admin@infinite-table.com"&gt; &lt;/a&gt;&lt;a href="mailto:admin@infinite-table.com"&gt;admin@infinite-table.com&lt;/a&gt;  or follow us &lt;a href="https://twitter.com/get_infinite"&gt;@get_infinite&lt;/a&gt; to keep up-to-date with news about the product. &lt;/p&gt;

&lt;p&gt;Talk soon 🙌&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Grouping and aggregation in React - made easy by Infinite Table</title>
      <dc:creator>Infinite Table</dc:creator>
      <pubDate>Mon, 28 Nov 2022 11:33:17 +0000</pubDate>
      <link>https://dev.to/get_infinite/grouping-and-aggregation-in-react-made-easy-by-infinite-table-564</link>
      <guid>https://dev.to/get_infinite/grouping-and-aggregation-in-react-made-easy-by-infinite-table-564</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/3NgNK8oattg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Check out our &lt;a href="https://infinite-table.com/docs/learn/grouping-and-pivoting/group-aggregations" rel="noopener noreferrer"&gt;documentation on aggregations&lt;/a&gt; and let us know how easy it was to get started.&lt;/p&gt;

&lt;p&gt;We're here to assist and help you to setup Infinite Table in your own React project 🎉&lt;/p&gt;

&lt;p&gt;Use the comments below to ask any question, and if needed, we can even jump in a zoom call to help 🎆&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Why Another React DataGrid?</title>
      <dc:creator>Infinite Table</dc:creator>
      <pubDate>Mon, 21 Nov 2022 11:41:50 +0000</pubDate>
      <link>https://dev.to/get_infinite/why-another-react-datagrid-j34</link>
      <guid>https://dev.to/get_infinite/why-another-react-datagrid-j34</guid>
      <description>&lt;p&gt;We've been working on finding better ways to display tabular data for over 2 decades now and collectively we have 35+ years of experience working on this.&lt;/p&gt;

&lt;p&gt;It all began on the desktop with a great range of DataGrids and then we moved to the web and the &lt;code&gt;&amp;lt;table /&amp;gt;&lt;/code&gt; component - yeah, we've been around for quite some while - all the while dealing with the same problems and requirements again and again. &lt;/p&gt;

&lt;p&gt;This is the story of how we got to where we are today....&lt;/p&gt;

&lt;h2&gt;
  
  
  A (personal) History of DataGrids
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;This article is not meant to be a complete history of DataGrids. &lt;br&gt;
Rather, it's personal reflections on the long journey the Infinite Table team have experienced while using and building components for displaying tabular data, culminating in Infinite Table, the modern declarative DataGrid for React.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Desktop Components
&lt;/h2&gt;

&lt;p&gt;DataGrids have been around as long as any of us can remember.&lt;/p&gt;

&lt;p&gt;They are a vital tool which allows business users to visualise, edit, manage and personalise their data.&lt;/p&gt;

&lt;p&gt;Before Tim Berners-Lee and his colleagues changed the world for ever (and for a couple of decades after), "serious" business applications lived on the desktop.&lt;/p&gt;

&lt;p&gt;This was accompanied and facilitated by a plethora of great DataGrids from the likes of DevExpress, Telerik, Syncfusion, Infragistics and others.&lt;/p&gt;

&lt;p&gt;These products defined the feature-set that users came to expect in a DataGrid - row grouping, formatting, multiple sorting, pivoting etc. &lt;/p&gt;

&lt;p&gt;And which any DataGrid worth its salt today needs to offer today.&lt;/p&gt;

&lt;p&gt;For 2 decades and more these DataGrid repeatedly proved their worth in multiple changing desktop formats - MFC, WinForms, WPF and others.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter the Browser
&lt;/h2&gt;

&lt;p&gt;And then the browser came along and, in time, everything changed.&lt;/p&gt;

&lt;p&gt;While it really took until HTML5 to convince most power users to move from the desktop to the web, the need to display tabular data in the browser was there right from the start.&lt;/p&gt;

&lt;p&gt;Initially the only way to show tabular data in the browser was to use the &lt;code&gt;&amp;lt;table /&amp;gt;&lt;/code&gt; component, and it was this piece of code that made it happen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;table-layout&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;fixed&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this is telling the browser (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout#values"&gt;see MDN&lt;/a&gt;) that it shouldn't compute the space available for all rows &amp;amp; cells in the table before rendering but instead size the columns based on the content of the first row. This is speeding up the rendering time by quite a lot, and it's the early solution to the problem of rendering large data-sets.&lt;/p&gt;

&lt;p&gt;However, it was not perfect, and rendering &lt;strong&gt;large&lt;/strong&gt; datasets was still a &lt;strong&gt;huge&lt;/strong&gt; problem. Also, no fancy resizable / reorderable / stackable columns were available - at least not by default.&lt;/p&gt;

&lt;p&gt;These shortcomings were obvious to developers dealing with massive datasets, so various groups and companies started coming up with solutions. One such solution came from Yahoo! as part of their larger widget library called &lt;code&gt;YUI&lt;/code&gt; (it was back in the days when Y! was a big deal).&lt;/p&gt;

&lt;h3&gt;
  
  
  YUI DataTable
&lt;/h3&gt;

&lt;p&gt;Enter YUI era - launched in 2006, the Yahoo! User Interface Library was a step forward in reusability and component architecture. With the release of YUI 3, it received a modernized set of components, and the &lt;a href="https://clarle.github.io/yui3/yui/docs/datatable/"&gt;YUI DataTable&lt;/a&gt; was probably the most advanced DataGrid solution out there. The component had a templating engine under the hood and allowed developers to customize some parts of the table. For its time, it was packed with functionality and was a great solution for many use-cases. &lt;/p&gt;

&lt;p&gt;It had a rich API, exposing lots of events, callbacks and methods for things like moving columns around, getting the data record for a given row, adding rows and columns, etc - all imperative code. The API was powerful and allowed developers to build complex solutions, but it was all stateful and imperative - something very normal for its epoch, but something we've learned to avoid in the last few years.&lt;/p&gt;

&lt;p&gt;Here's some code showcasing the YUI DataTable&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DataTable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;125px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;formatter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;£: {value}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;sortable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;sortable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;   &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#example&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// to programatically sort&lt;/span&gt;
&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;asc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice in the code above, the component had support for custom formatters via a template (in the style of Mustache templates). YUI DataTable was a great component, certainly lacking some features by modern standards, but it was amazingly rich for its time. In some respects, it's still better than some of the modern DataGrids out there. The major missing piece is virtualization for both rows and columns in the table.&lt;/p&gt;

&lt;p&gt;A nice feature YUI DataTable had was the ability to separate the DataSource component and the data loading into a separate abstraction layer, so it would be somewhat decoupled from the main UI component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dataSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IO&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/restaurants/fetch.php?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;dataSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Plugin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DataSourceXMLSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;resultListLocator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Result&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;resultFields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Phone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rating&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DataTable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Phone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rating&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Chinese restaurants near 98089&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Plugin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DataTableDataSource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;datasource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dataSource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;initialRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zip=94089&amp;amp;query=chinese&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Infinite Table is getting this a step further and splitting the data loading and the rendering into two separate components - &lt;code&gt;&amp;lt;DataSource /&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;InfiniteTable /&amp;gt;&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;&amp;lt;DataSource /&amp;gt;&lt;/code&gt; component is responsible for managing the data - fetching it, sorting, grouping, pivoting, filtering, etc and making it available via the React context to the UI component.&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;&amp;lt;InfiniteTable /&amp;gt;&lt;/code&gt; component is responsible only for rendering the data. This means you can even use the &lt;code&gt;&amp;lt;DataSource /&amp;gt;&lt;/code&gt; component with another React component and implement your own rendering and virtualization.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataSource&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="na"&gt;DataEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; primaryKey="id" data=&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&amp;gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* if you wanted to, you can replace
   &amp;lt;InfiniteTable/&amp;gt; with your own custom component */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InfiniteTable&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="na"&gt;DataEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; columns=&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&amp;gt; 
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This level of separation allows us to iterate more rapidly on new features and also makes testing 🧪 easier.&lt;/p&gt;

&lt;h3&gt;
  
  
  ExtJS 3
&lt;/h3&gt;

&lt;p&gt;The next solution we've worked with was &lt;a href="https://docs.sencha.com/extjs/3.4.0/#!/api/Ext.grid.GridPanel"&gt;ExtJS version 3&lt;/a&gt;, which was built on the legacy of YUI 3. At the time, back in 2010, it was the most advanced DataGrid solution out there - used for some of the most complex applications in the enterprise world, from CMSs to ERP systems. &lt;/p&gt;

&lt;p&gt;The ExtJS 3 DataGrid brought excellent product execution in a few areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;a href="https://docs.sencha.com/extjs/3.4.0/"&gt;documentation&lt;/a&gt; was excellent for its time - very rich, easy to navigate and search, with useful examples. As a bonus, from the docs you had access to the source-code of all components, which was a nice addition.&lt;/li&gt;
&lt;li&gt;it came together with a rich set of components for building complex UIs - grids, trees, combo-boxes, form inputs, menus, dialogs, etc. Powerful layout components were available, which allowed developers to build complex app layouts by composing components together - and everything felt like it was part of the same story, which it was.&lt;/li&gt;
&lt;li&gt;enthusiastic community - the forums were very active and the community was writing lots of good plugins.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Ext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GridPanel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// data fetching abstracted in a "Store" component&lt;/span&gt;
  &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Ext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="c1"&gt;// columns abstracted in a ColumnModel&lt;/span&gt;
  &lt;span class="na"&gt;colModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Ext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ColumnModel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sortable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;company&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Company&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;sortable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dataIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;company&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Price&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Ext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usMoney&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dataIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;price&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dataIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;% Change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dataIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pctChange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Last Updated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;135&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dataIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lastChange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;xtype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;datecolumn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;M d, Y&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;viewConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;forceFit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// Return CSS class to apply to rows depending upon data values&lt;/span&gt;
    &lt;span class="na"&gt;getRowClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;price-fall&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;price-rise&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Ext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RowSelectionModel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;singleSelect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="c1"&gt;// size need if not inside a layout&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Building on the legacy of YUI 3, the ExtJS added virtualization to make the DataGrid perform well for large datasets - it really made the component fly - since there was no framework overhead, and ExtJS was working directly with the DOM, the scrolling experience was pretty smooth.&lt;/p&gt;

&lt;p&gt;Also ExtJS tried to make things declarative and you could describe most of your UI by nesting JavaScript objects into a root object. The idea was clever, but it was only applicable for the initial rendering and you had to write imperative code as soon as you wanted some changes after the initial render. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It was while working on a project with ExtJS 3 and exploring everything it had to offer that we had the great idea 😅 that we should start writing a DataGrid component. &lt;/p&gt;

&lt;p&gt;We were digging deep into ExtJS source code, wrote a few plugins for it and then decided to take the challenge and build a brand new DataGrid 😱. &lt;/p&gt;

&lt;p&gt;It was supposed to take us just a few short months 😅...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The React Revolution
&lt;/h2&gt;

&lt;p&gt;We were quite far in building the DataGrid component, with a dedicated templating engine under the hood (by the way, it was really good in comparison to similar solutions at that time), virtualization implemented and major functionalities finished ... when JSConf EU 2013 happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  JSConf EU 2013
&lt;/h3&gt;

&lt;p&gt;We vividly remember &lt;a href="https://www.youtube.com/watch?v=x7cQ3mrcKaY"&gt;watching Pete Hunt talk about ReactJS and rethinking best practices&lt;/a&gt; at JSConf EU 2013.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/x7cQ3mrcKaY?start=25"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;By the time the presentation was finished we knew we had to do something.&lt;/p&gt;

&lt;p&gt;This declarative way of describing the UI got us hooked and we knew we had to &lt;strong&gt;drop what we were doing and adopt React&lt;/strong&gt; for anything going forward. It proved to be the right decision and we were early adopters of &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt;. It was astonishing to us how easy it was to learn React at the time - only taking a few hours to fully grasp the mental model and start building reusable components.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
2013 was the year we switched trajectory and went full-React with all our new projects. We went back to the drawing board and started our first experiments with a DataGrid component in React. &lt;br&gt;
&lt;/p&gt;

&lt;p&gt;While we were building the DataGrid in React we got side-tracked with other projects but we saw the same pattern again and again - people trying to implement the grid component again and again, in various projects. Most of those attempts either failed terribly or at best they were good-enough for a simple use-case.&lt;/p&gt;

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

&lt;p&gt;It was around this time, in 2015, that &lt;a href="https://www.ag-grid.com/"&gt;AG Grid&lt;/a&gt; was launched. &lt;/p&gt;

&lt;p&gt;And, wow, it was good - very good.&lt;/p&gt;

&lt;p&gt;We immediately adopted it in all kind of projects while still trying to find time on the side to build our own DataGrid solution, the React way, with a fully declarative API.&lt;/p&gt;

&lt;p&gt;We were inspired 🙏 by AG Grid, seeing the breadth of features it offers and its expansive growth. &lt;/p&gt;

&lt;p&gt;It is a feat of engineering which illustrates just how much the browser can be pushed by extensive use of virtualization - being able to render millions of rows and thousands of columns is no small feat. &lt;/p&gt;

&lt;p&gt;All this while keeping the performance similar as if it was rendering just a few rows and columns.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/infallible-waterfall-csjcns?module=%2Findex.js"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In the code above (&lt;a href="https://www.ag-grid.com/javascript-data-grid/getting-started/#copy-in-application-code"&gt;taken from AG Grid getting started page&lt;/a&gt;), note that AG Grid is exposing its &lt;a href="https://www.ag-grid.com/javascript-data-grid/grid-api/"&gt;API&lt;/a&gt; on the &lt;code&gt;gridOptions&lt;/code&gt; object. &lt;/p&gt;

&lt;p&gt;The API is huge and allow you to do pretty much anything you want with the grid - in an imperative way, which is what you're probably looking for if you're not integrating with a library/framework like Angular or React.&lt;/p&gt;

&lt;p&gt;After vanilla JavaScript and Angular versions of AG Grid, a React version was finally released. &lt;/p&gt;

&lt;p&gt;It was a step in the right direction - to make AG Grid more declarative - though it was a thin wrapper around React, with all the renderers and API still being imperative and not feeling like the best fit inside a React app.&lt;/p&gt;

&lt;p&gt;A few years later, AG Grid finally released a &lt;code&gt;reactUI&lt;/code&gt; &lt;a href="https://blog.ag-grid.com/react-ui-overview/"&gt;version&lt;/a&gt;, with tighter integration with React and a more declarative API ❤️&lt;/p&gt;

&lt;p&gt;All this time other solutions popped up in the React community.&lt;/p&gt;

&lt;h3&gt;
  
  
  React Table
&lt;/h3&gt;

&lt;p&gt;One such solution that got massive adoption from the community was &lt;a href="https://tanstack.com/table/v8/"&gt;React Table&lt;/a&gt; - now rebranded as TanStack Table.&lt;/p&gt;

&lt;p&gt;It's growth began around 2018, around the time when headless UI components started to gain traction. &lt;/p&gt;

&lt;p&gt;React Table was one of the first popular headless UI components to be released - in the same category it's worth mentioning &lt;a href="https://www.downshift-js.com/"&gt;Downshift&lt;/a&gt; (initially launched and popularized by &lt;a href="https://kentcdodds.com/"&gt;Kent C. Dodds&lt;/a&gt;), which helped push headless UI components to the community.&lt;/p&gt;

&lt;p&gt;React Table is a great solution for people who want to build their own UI on top of it. &lt;/p&gt;

&lt;p&gt;Some of the benefits of headless UI approach you get from React Table are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;full control over markup and styles&lt;/li&gt;
&lt;li&gt;supports all styling patterns (CSS, CSS-in-JS, UI libraries, etc)&lt;/li&gt;
&lt;li&gt;smaller bundle-sizes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This flexibility and total control come with a cost of needing more setup, more code and more maintainance over time. Also complex features that might already be implemented in a full-featured DataGrid will need to be implemented again from scratch.&lt;/p&gt;

&lt;p&gt;However, we do think it's a great 💯 fit for some use-cases - we've used it ourselves successfully in some projects 🙏. But it's not for everyone, as in our experience, most teams today want to ship faster 🏎 and not spend time and mental energy on building their own UI.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/github?module=%2Fsrc%2Fmain.tsx"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Notice in the code above how you're responsible for creating the markup for the table, the headers, column groups,the cells, etc. You have TOTAL control over overy aspect of the component, but this means you have to own it!&lt;/p&gt;

&lt;p&gt;At the other end of the spectrum is AG Grid a full-featured DataGrid that offers all this out of the box. &lt;/p&gt;

&lt;p&gt;With Infinite Table, we're trying to strike a balance between these 2 very different approaches - by offering a declarative API that is easy to use and get started with, while still giving you the flexibility to customize the UI and the behavior of the component, via both controlled and uncontrolled props.&lt;/p&gt;

&lt;p&gt;Let's take a look at an example of a similar UI, this time built with Infinite Table.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/infinite-table-with-column-groups-2nn8zc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Infinite Table
&lt;/h2&gt;

&lt;p&gt;All this time we kept an eye on other components out there to get inspired. We got fresh ideas from various teams and projects - either enterprise or open source - either full-fledged or headless components like &lt;a href="https://tanstack.com/table/v8/"&gt;react-table&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We've learned a lot from all these projects we've worked with and we've put all the best ideas in Infinite Table.&lt;/p&gt;

&lt;p&gt;Infinite is the fruit of years of iteration, experimentation, failures and sweat on a product that we've poured our hearts in over the course of so many years. We've agonized over all our APIs and design decisions in order to make Infinite Table the best React DataGrid component out there.&lt;/p&gt;

&lt;p&gt;We're aware we're not there yet, but we're here to stay 👋 and keep getting better. We want to work closely with the community at large and get fresh ideas from other projects and teams. We can all be winners when we work together and respect each-other ❤️&lt;/p&gt;

&lt;p&gt;It's amazing what happens when you focus on a problem for such a long time (yeah, we know 😱). We wanted to give up several times but kept pushing for over a decade. The result is a component that we're proud of and is already starting to be used by enterprise clients across many industries (more on that in a later blogpost).&lt;/p&gt;

&lt;p&gt;Here are some of the key areas where we believe Infinite Table shines:&lt;/p&gt;

&lt;h3&gt;
  
  
  Ready to Use
&lt;/h3&gt;

&lt;p&gt;Infinite Table is ready to use out of the box - namely it's not headless. We target customers who want to ship — faster 🏎! We're aware you don't want to re-invent the wheel nor do you want to invest 6 months of your team to build a poor implementation of a DataGrid component that will be hard to maintain and will be a source of bugs and frustration. &lt;strong&gt;You want to ship — and soon!&lt;/strong&gt;. If this is you and you are already using React then Infinite Table is written for you!&lt;/p&gt;

&lt;h3&gt;
  
  
  Feels like React - Declarative API
&lt;/h3&gt;

&lt;p&gt;We want Infinite Table to feel at home in any React app. Everything about the DataGrid should be declarative - when you want to update the table, change a prop and the table will respond. No imperative API calls - we want you to be able to use Infinite Table in a way that feels natural to you and your team, so you can stay productive and use React everywhere in your frontend. &lt;/p&gt;

&lt;p&gt;Let's take for example how you would switch a column from a column group to another:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getColumns&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;columnGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;personalInfo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;columnGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;personalInfo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;age&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;columnGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;about&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;InfiniteTablePropColumns&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DataType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;columnGroups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;personalInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Personal info&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;about&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;About&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setColumns&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;InfiniteTablePropColumns&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DataType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getColumns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;colGroupForAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setColGroupForAddress&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;personalInfo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toggle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cols&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getColumns&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newColGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;colGroupForAddress&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;personalInfo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;about&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;personalInfo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="nx"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;columnGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newColGroup&lt;/span&gt;

    &lt;span class="nx"&gt;setColumns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;setColGroupForAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newColGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;btn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; Toggle group for address &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;btn&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataSource&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="na"&gt;DataType&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; data=&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; primaryKey="id"&amp;gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InfiniteTable&lt;/span&gt; &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;columnGroups&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;columnGroups&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note in the code above that in order to update the column group for the &lt;code&gt;address&lt;/code&gt; column, we simply change the &lt;code&gt;columnGroup&lt;/code&gt; prop of the column and then we update the state of the component. The table will automatically re-render and update the column group for the &lt;code&gt;address&lt;/code&gt; column. This is a fully declarative way to update the table. You don't need to call any imperative API to update it - change the props and the table will reflect the changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fully Controlled
&lt;/h3&gt;

&lt;p&gt;React introduced controlled components to the wider community and we've been using them for years. It's were the power of React lies - it gives the developer the flexibility to fully control (when needed) every input point of an app or component.&lt;/p&gt;

&lt;p&gt;All the props Infinite Table is exposing have both controlled and uncontrolled versions. This allows you to start using the component very quickly and without much effort, but also gives you the flexibility to fully control the component when needed, as your app grows and you need more control over the DataGrid.&lt;/p&gt;

&lt;h3&gt;
  
  
  Composable API with small API surface
&lt;/h3&gt;

&lt;p&gt;When building a complex component, there are two major opposing forces: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;adding functionality and &lt;/li&gt;
&lt;li&gt;keeping the component (and the API) simple.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We're trying to reconcile both with Infinite Table so we've built everything with composition in mind.&lt;/p&gt;

&lt;p&gt;A practical example of composition is favoring function props instead of boolean flags or objects. Why implement a feature under a boolean flag or a static object when you can expose a functionality via a function prop? The function prop can be used to handle more cases than any boolean flag could ever handle!&lt;/p&gt;

&lt;p&gt;A good example of composability is the  prop - it can be a column object or a function. It control the columns that are generated for grouping:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when it's a column object, it makes the table render a single column for grouping (as if  was set to &lt;code&gt;"single-column"&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;when it's a function, it behaves like  is set to &lt;code&gt;"multi-column"&lt;/code&gt; and it's being called for each of the generated columns.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InfiniteTable&lt;/span&gt; 
  &lt;span class="c1"&gt;//...&lt;/span&gt;
  &lt;span class="na"&gt;groupColumn&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Groups&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;vs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InfiniteTable&lt;/span&gt; 
  &lt;span class="c1"&gt;//...&lt;/span&gt;
  &lt;span class="na"&gt;groupColumn&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// this allows you to affect all generated group columns in a single place&lt;/span&gt;
    &lt;span class="c1"&gt;// especially useful when the generated columns are dynamic or generated via a pivot&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've learned from our experience with other DataGrid components that the more features you add, the more complex your API becomes. So we tried to keep the API surface as small as possible, while still offering a rich set of declarative props as building blocks that can be composed to accomplish more complex functionalities.&lt;/p&gt;

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

&lt;p&gt;We're very excited to share our Infinite Table journey with you  ❤️ 🤩&lt;/p&gt;

&lt;p&gt;After years in the DataGrid space and working and agonizing on this component, we're happy to finally ship it 🛳 🚀. &lt;/p&gt;

&lt;p&gt;We're looking forward to receiving &lt;a href="https://github.com/infinite-table/infinite-react/issues"&gt;your feedback&lt;/a&gt; and suggestions.&lt;/p&gt;

&lt;p&gt;We're here to stay and we're committed to improving Infinite Table and to make it your go-to React DataGrid component to help you ship — faster! All the while staying true to the community!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>html</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Infinite Table Monthly Update - August 2022</title>
      <dc:creator>Infinite Table</dc:creator>
      <pubDate>Tue, 06 Sep 2022 11:23:41 +0000</pubDate>
      <link>https://dev.to/get_infinite/infinite-table-monthly-update-august-2022-3484</link>
      <guid>https://dev.to/get_infinite/infinite-table-monthly-update-august-2022-3484</guid>
      <description>&lt;p&gt;At &lt;a href="https://infinite-table.com"&gt;Infinite Table&lt;/a&gt;, we continued our work on preparing for our Autumn release,  focusing mainly on adding new functionalities and documenting them thoroughly, together with enhancements to existing features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We have implemented a few new functionalities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;row selection is now available&lt;/li&gt;
&lt;li&gt;column rendering pipeline&lt;/li&gt;
&lt;li&gt;group columns are now sortable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And we have updated some of the existing features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
group columns inherit styles and configuration&lt;/li&gt;
&lt;li&gt;column hiding when grouping&lt;/li&gt;
&lt;li&gt;group columns can be bound to a field&lt;/li&gt;
&lt;li&gt;using the column valueGetter in sorting&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Coming soon
&lt;/h2&gt;

&lt;p&gt;We started working on column and context menus.&lt;br&gt;
We will first release fully customizable &lt;strong&gt;column&lt;/strong&gt; menus to show/hide columns and to easily perform other operations on columns.&lt;br&gt;
This will be followed by &lt;strong&gt;context&lt;/strong&gt; menus where you will be able to define your own custom actions on rows/cells in the table.&lt;/p&gt;



&lt;p&gt;Don't worry, the menus will be fully customizable, the menu items are fully replaceable with whatever you need, or you will be able to swap our menu component with a custom one of your own.&lt;/p&gt;
&lt;h2&gt;
  
  
  New Features
&lt;/h2&gt;

&lt;p&gt;Here's what we shipped in the month of August:&lt;/p&gt;
&lt;h3&gt;
  
  
  Row Selection
&lt;/h3&gt;

&lt;p&gt;Row selection can be single or multiple, with or without a checkbox, with or without grouping and for a lazy or non-lazy &lt;code&gt;DataSource&lt;/code&gt; - 😅 that was a long enumeration, but seriously, we think we got something great out there.&lt;/p&gt;

&lt;p&gt;You can specify the selection via the &lt;a href="https://infinite-table.com/docs/latest/reference/datasource-props#rowSelection"&gt;rowSelection&lt;/a&gt; (controlled) or &lt;a href="https://infinite-table.com/docs/latest/reference/datasource-props#defaultRowSelection"&gt;defaultRowSelection&lt;/a&gt; (uncontrolled) props, and listen to changes via the &lt;a href="https://infinite-table.com/docs/latest/reference/datasource-props#onRowSelectionChange"&gt;onRowSelectionChange&lt;/a&gt; callback prop.&lt;/p&gt;

&lt;p&gt;This example shows how you can use multiple row selection with a predefined controlled value.&lt;/p&gt;

&lt;p&gt;Go ahead and select some groups/rows and see the selection value adjust.&lt;/p&gt;

&lt;p&gt;The example also shows how you can use the &lt;a href="https://infinite-table.com/docs/latest/reference/api"&gt;InfiniteTableApi&lt;/a&gt; to retrieve the actual ids of the selected rows.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/sandpack-project-cdx0yh"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://infinite-table.com/docs/latest/learn/selection/row-selection"&gt;Find out more on row selection&lt;/a&gt; - single vs multiple selection, grouped or ungrouped data, checkbox selection, lazy selection - read about all the possible combinations you can use to fit your needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Column Rendering Pipeline
&lt;/h3&gt;

&lt;p&gt;The rendering pipeline for columns is a series of functions defined on the column that are called while rendering.&lt;/p&gt;

&lt;p&gt;Most of those functions existed even before, but piping the return values from one to the other was not available. We think this is a big deal and opens up lots of use-cases.&lt;/p&gt;

&lt;p&gt;All the columns that have &lt;code&gt;render&lt;/code&gt; in their name, will be called with an object that has a &lt;code&gt;renderBag&lt;/code&gt; property on it, which contains the values that the previous function in the pipeline returned.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InfiniteTableColumn&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;valueGetter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;field&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;renderValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;renderBag&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// accessing `value` here would give us the result from `data[field]`&lt;/span&gt;
    &lt;span class="c1"&gt;// but using `renderBag.value` would give us `data[field] * 10`, &lt;/span&gt;
    &lt;span class="c1"&gt;// namely the result of the previous function in the pipeline&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InfiniteTableColumn&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;renderGroupIcon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;renderBag&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// we can use `renderBag.groupIcon` to have access to the default group icon and decorate it&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;b&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;renderBag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;groupIcon&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;b&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;renderBag&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// allows you to fully customize the end-result&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;renderBag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;renderBag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;groupIcon&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;renderBag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectionCheckBox&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are all the properties available in the &lt;code&gt;renderBag&lt;/code&gt; object:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;value&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;groupIcon&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;selectionCheckBox&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the full list of the functions in the rendering pipeline, in order of invocation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/latest/reference#columns.valueGetter"&gt;columns.valueGetter&lt;/a&gt; - doesn't have access to &lt;code&gt;renderBag&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/latest/reference#columns.valueFormatter"&gt;columns.valueFormatter&lt;/a&gt; - doesn't have access to &lt;code&gt;renderBag&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/latest/reference#columns.renderGroupIcon"&gt;columns.renderGroupIcon&lt;/a&gt; - can use all properties in &lt;code&gt;renderBag&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/latest/reference#columns.renderSelectionCheckBox"&gt;columns.renderSelectionCheckBox&lt;/a&gt; - can use all properties in &lt;code&gt;renderBag&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/latest/reference#columns.renderValue"&gt;columns.renderValue&lt;/a&gt; - can use all properties in &lt;code&gt;renderBag&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/latest/reference#columns.renderGroupValue"&gt;columns.renderGroupValue&lt;/a&gt; - can use all properties in &lt;code&gt;renderBag&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/latest/reference#columns.renderLeafValue"&gt;columns.renderLeafValue&lt;/a&gt; - can use all properties in &lt;code&gt;renderBag&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infinite-table.com/docs/latest/reference#columns.render"&gt;columns.render&lt;/a&gt; - can use all properties in &lt;code&gt;renderBag&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Additionally, the&lt;a href="https://infinite-table.com/docs/latest/reference#columns.components.ColumnCell"&gt;columns.components.ColumnCell&lt;/a&gt; custom component has access to the &lt;code&gt;renderBag&lt;/code&gt; via &lt;a href="https://infinite-table.com/docs/latest/reference/hooks#useInfiniteColumnCell"&gt;useInfiniteColumnCell&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Sortable Group Columns
&lt;/h3&gt;

&lt;p&gt;When &lt;a href="https://infinite-table.com/docs/latest/reference#groupRenderStrategy"&gt;groupRenderStrategy&lt;/a&gt; is used, the group column is sortable by default if all the columns that are involved in grouping are sortable.&lt;/p&gt;

&lt;p&gt;Sorting the group column makes the &lt;code&gt;sortInfo&lt;/code&gt; have a value that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sortInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;age&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;group-by&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;a href="https://infinite-table.com/docs/latest/reference#groupRenderStrategy"&gt;groupRenderStrategy="multi-column"&lt;/a&gt;, each group column is sortable by default if the column with the corresponding field is sortable.&lt;/p&gt;

&lt;p&gt;In both single and multi group column render strategy, the &lt;a href="https://infinite-table.com/docs/latest/reference#columns.sortable"&gt;columns.sortable&lt;/a&gt; property can be used to override the default behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updated Features
&lt;/h2&gt;

&lt;p&gt;Here’s a list of Infinite Table functionalities that we enhanced in the last month:&lt;/p&gt;

&lt;h3&gt;
  
  
  Enhanced Group Columns
&lt;/h3&gt;

&lt;p&gt;Group columns now inherit configuration from the columns bound to the field they are grouped by - if such columns exist.&lt;/p&gt;

&lt;p&gt;In this example, the group column inherits the styling of the &lt;code&gt;country&lt;/code&gt; column, because the &lt;code&gt;country&lt;/code&gt; field is used for grouping.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/sandpack-project-ybml8s"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The generated group column(s) - can be one for all groups or one for each group - will inherit the &lt;code&gt;style&lt;/code&gt;/&lt;code&gt;className&lt;/code&gt;/renderers from the columns corresponding to the group fields themselves (if those columns exist).&lt;/p&gt;

&lt;p&gt;Additionally, there are other ways to override those inherited configurations, in order to configure the group columns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use &lt;a href="https://infinite-table.com/docs/latest/reference/datasource-props#groupBy"&gt;groupBy.column&lt;/a&gt; to specify how each grouping column should look for the respective field (in case of &lt;a href="https://infinite-table.com/docs/latest/reference#groupRenderStrategy"&gt;groupRenderStrateg="multi-column"&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;use &lt;a href="https://infinite-table.com/docs/latest/reference#groupColumn"&gt;groupColumn&lt;/a&gt; prop 

&lt;ul&gt;
&lt;li&gt;can be used as an object - ideal for when you have simple requirements and when &lt;a href="https://infinite-table.com/docs/latest/reference#groupRenderStrategy"&gt;groupRenderStrateg="single-column"&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;as a function that returns a column configuration - can be used like this in either single or multiple group render strategy&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Column Hiding when Grouping
&lt;/h3&gt;

&lt;p&gt;When grouping is enabled, you can choose to hide some columns. Here are the two main ways to do this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use &lt;a href="https://infinite-table.com/docs/latest/reference#hideColumnWhenGrouped"&gt;hideColumnWhenGrouped&lt;/a&gt; - this will make columns bound to the group fields be hidden when grouping is active&lt;/li&gt;
&lt;li&gt;use &lt;a href="https://infinite-table.com/docs/latest/reference#columns.defaultHiddenWhenGroupedBy"&gt;columns.defaultHiddenWhenGroupedBy&lt;/a&gt; (also available on the column types, as &lt;a href="https://infinite-table.com/docs/latest/reference#columnTypes"&gt;columnTypes.defaultHiddenWhenGroupedBy&lt;/a&gt;) - this is a column-level property, so you have more fine-grained control over what is hidden and when.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Valid values for &lt;a href="https://infinite-table.com/docs/latest/reference#columns.defaultHiddenWhenGroupedBy"&gt;columns.defaultHiddenWhenGroupedBy&lt;/a&gt; are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;"*"&lt;/code&gt; - when any grouping is active, hide the column that specifies this property&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;true&lt;/code&gt; - when the field this column is bound to is used in grouping, hides this column&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;keyof DATA_TYPE&lt;/code&gt; - specify an exact field that, when grouped by, makes this column be hidden&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{[k in keyof DATA_TYPE]: true}&lt;/code&gt; - an object that can specify more fields. When there is grouping by any of those fields, the current column gets hidden.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this example, the column bound to &lt;code&gt;firstName&lt;/code&gt; field is set to hide when any grouping is active, since the group column is anyways found to the &lt;code&gt;firstName&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;In addition, &lt;a href="https://infinite-table.com/docs/latest/reference#hideColumnWhenGrouped"&gt;hideColumnWhenGrouped&lt;/a&gt; is set to &lt;code&gt;true&lt;/code&gt;, so the &lt;code&gt;stack&lt;/code&gt; and &lt;code&gt;preferredLanguage&lt;/code&gt; columns are also hidden, since they are grouped by.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/sandpack-project-d41t32"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Group Columns Bound to a Field
&lt;/h3&gt;

&lt;p&gt;Group columns can now be bound to a field, by leveraging the (obviously ...)  property. This will make the group column render the value of that field for non-group rows.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/sandpack-project-ni8xs0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In addition, you can now use &lt;a href="https://infinite-table.com/docs/latest/reference#columns.renderGroupValue"&gt;columns.renderGroupValue&lt;/a&gt; and &lt;a href="https://infinite-table.com/docs/latest/reference#columns.renderLeafValue"&gt;columns.renderLeafValue&lt;/a&gt; for configuring the rendered value for grouped vs non-grouped rows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Column valueGetter in Sorting
&lt;/h3&gt;

&lt;p&gt;Columns allow you to define a &lt;a href="https://infinite-table.com/docs/latest/reference#columns.valueGetter"&gt;columns.valueGetter&lt;/a&gt; to change the value they are rendering (eg: when the &lt;code&gt;DataSet&lt;/code&gt; has nested objects). Previously, this value returned by &lt;a href="https://infinite-table.com/docs/latest/reference#columns.valueGetter"&gt;columns.valueGetter&lt;/a&gt; was not used when sorting the table. With the latest updated, the value returned by &lt;code&gt;valueGetter&lt;/code&gt; is correctly used when sorting the grid locally.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What's the most useful feature for a DataGrid?</title>
      <dc:creator>Infinite Table</dc:creator>
      <pubDate>Wed, 29 Jun 2022 20:59:03 +0000</pubDate>
      <link>https://dev.to/get_infinite/whats-the-most-useful-feature-for-a-datagrid-3m13</link>
      <guid>https://dev.to/get_infinite/whats-the-most-useful-feature-for-a-datagrid-3m13</guid>
      <description>&lt;p&gt;As we're building &lt;a href="https://infinite-table.com/"&gt;https://infinite-table.com/&lt;/a&gt; we know the it will be used in ways we haven't imagined yet - so we're developing the component with this flexibility in mind.&lt;/p&gt;

&lt;p&gt;However, we're here to ask the community:&lt;/p&gt;

&lt;h3&gt;
  
  
  What do you want most from a DataGrid?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  What's one feature that would immediately make you use Infinite Table?
&lt;/h3&gt;

</description>
      <category>discuss</category>
      <category>javascript</category>
      <category>react</category>
      <category>html</category>
    </item>
    <item>
      <title>How do you fetch and process your data</title>
      <dc:creator>Infinite Table</dc:creator>
      <pubDate>Tue, 07 Jun 2022 10:32:00 +0000</pubDate>
      <link>https://dev.to/get_infinite/how-do-you-fetch-and-process-your-data-1icm</link>
      <guid>https://dev.to/get_infinite/how-do-you-fetch-and-process-your-data-1icm</guid>
      <description>&lt;p&gt;Let's discuss - how do you fetch your tabular data?&lt;br&gt;
Do you load it initially and then only do client side processing?&lt;br&gt;
How do you sort - local or remote sorting? What about filtering?&lt;br&gt;
Do you use grouping or pivoting - and if so, does it happen in the browser?&lt;br&gt;
Keen to find out how other people do it 🤔&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Navigating your react datagrid</title>
      <dc:creator>Infinite Table</dc:creator>
      <pubDate>Tue, 07 Jun 2022 10:25:38 +0000</pubDate>
      <link>https://dev.to/get_infinite/navigating-your-react-datagrid-42h5</link>
      <guid>https://dev.to/get_infinite/navigating-your-react-datagrid-42h5</guid>
      <description>&lt;p&gt;Using your keyboard to navigate around an app is crucial to moving fast and being productive.&lt;/p&gt;

&lt;p&gt;With version &lt;code&gt;0.3.6&lt;/code&gt; &lt;a href="https://infinite-table.com"&gt;Infinite Table&lt;/a&gt; just added keyboard navigation to your favorite React DataGrid component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Navigating table cells
&lt;/h2&gt;

&lt;p&gt;By default, navigation is enabled for table cells - that means, as soon as the user clicks a cell, it becomes active and from that point onwards, the user can use arrow keys, page up/down and home/end keys to navigate.&lt;/p&gt;

&lt;p&gt;Check out our &lt;a href="https://infinite-table.com/docs/latest/learn/keyboard-navigation/navigating-cells"&gt;documentation for keyboard navigation&lt;/a&gt; to see more demos and a complete reference guide.&lt;/p&gt;

&lt;p&gt;Pro tip: when in cell navigation mode, you can use the &lt;code&gt;Shift&lt;/code&gt; key to navigate horizontally in combination with page up/down and home/end keys.&lt;/p&gt;

&lt;p&gt;In the example below, click a table cell and then use arrow keys to see keyboard navigation in action&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/sandpack-project-e9v7rv?view=preview"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Another nice feature of keyboard navigation for cells is that you can specify a default active cell - you do so by using &lt;code&gt;defaultActiveCell=[2,0]&lt;/code&gt; - meaning the cell on row 2 and column 0 should be active initially.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/sandpack-project-t6ogg5?view=preview"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Navigating table rows
&lt;/h2&gt;

&lt;p&gt;Besides cell navigation, row navigation is also available. Switch to row navigation mode by specifying &lt;code&gt;keyboardNavigation="row"&lt;/code&gt; - the rest is similar: user clicks a row, which becomes the active row. Using arrow keys, page up/down and home/end works as expected.&lt;/p&gt;

&lt;p&gt;Having a default row set as active is also possible, via &lt;code&gt;defaultActiveRowIndex={2}&lt;/code&gt; - this means the row at index &lt;code&gt;2&lt;/code&gt; should be initially rendered as active.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/sandpack-project-g7bcky?view=preview"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Controlling active row/cell
&lt;/h2&gt;

&lt;p&gt;Both cell and row navigation can be used as React uncontrolled and controlled behaviors.&lt;/p&gt;

&lt;p&gt;In the controlled version, you have to use &lt;code&gt;onActiveCellIndexChange&lt;/code&gt; (or &lt;code&gt;onActiveRowIndexChange&lt;/code&gt;) to respond to navigation changes and update the corresponding index.&lt;/p&gt;

&lt;p&gt;The example below demoes controlled cell navigation - initially starting with no active cell, and it updates the active cell as a result to user changes. This means you as a developer are responsible for updating the value when needed, as you no longer wish to leave this update to happen internally in the table. This makes controlled behavior excellent for advanced use-cases when you want to implement custom navigation logic.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/sandpack-project-forked-8njdhk?view=preview"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning off keyboard navigation
&lt;/h2&gt;

&lt;p&gt;Disabling keyboard navigation is done by specifying &lt;code&gt;keyboardNavigation=false&lt;/code&gt; - this ensures the user can no longer interact with the table rows or cells via the keyboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Theming
&lt;/h2&gt;

&lt;p&gt;There are a number of ways to customise the appearance of the element that highlights the active cell.&lt;/p&gt;

&lt;p&gt;The easiest is to override those three CSS variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--infinite-active-cell-border-color--r&lt;/code&gt; - the red component of the border color&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--infinite-active-cell-border-color--g&lt;/code&gt; - the green component of the border color&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--infinite-active-cell-border-color--b&lt;/code&gt; - the blue component of the border color&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The initial values for those are 77, 149 and215 respectively, so the border color is &lt;code&gt;rgb(77, 149, 215)&lt;/code&gt;.&lt;br&gt;
In addition, the background color of the active cell highlight element is set to the same color as the border color (computed based on the above r, g and b variables), but with an opacity of &lt;code&gt;0.25&lt;/code&gt;, configured via the &lt;code&gt;--infinite-active-cell-background-alpha&lt;/code&gt; CSS variable. &lt;/p&gt;

&lt;p&gt;When the table is not focused, the opacity for the background color is set to &lt;code&gt;0.1&lt;/code&gt;, which is the default value of the &lt;code&gt;--infinite-active-cell-background-alpha--table-unfocused&lt;/code&gt; CSS variable.&lt;/p&gt;

&lt;p&gt;To summarize, use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--infinite-active-cell-border-color--r&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--infinite-active-cell-border-color--g&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--infinite-active-cell-border-color--b&lt;/code&gt;
to control border and background color of the active cell highlight element.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See below a demo on how easy it is to customize the colors for the active element highlighter&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/sandpack-project-7ygsng?view=preview"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Enjoy
&lt;/h2&gt;

&lt;p&gt;Thanks for following us thus far - we appreciate feedback, so please to let us know if keyboard navigation is useful for you or how we could make it better.&lt;/p&gt;

&lt;p&gt;Please follow us &lt;a href="https://twitter.com/get_infinite"&gt;@get_infinite&lt;/a&gt; to keep up-to-date with news about the product. Thank you.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Grouping and aggregating your data like a pro 🚀</title>
      <dc:creator>Infinite Table</dc:creator>
      <pubDate>Thu, 26 May 2022 08:12:21 +0000</pubDate>
      <link>https://dev.to/get_infinite/grouping-and-aggregating-your-data-like-a-pro-3eoc</link>
      <guid>https://dev.to/get_infinite/grouping-and-aggregating-your-data-like-a-pro-3eoc</guid>
      <description>&lt;p&gt;In most modern apps, you need to be able to visualise your data in multiple different ways.  One useful approach to seeing data is by grouping it. What is the average salary by country?  How many sales did we have this year?  What was the biggest sale we had last quarter?  All are common questions that can be easily answered by grouping and aggregating data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://infinite-table.com/docs/latest/learn/grouping-and-pivoting/grouping-rows"&gt;Infinite Table&lt;/a&gt; can help you group your data easily, both locally and with a remote data-source.&lt;/p&gt;

&lt;p&gt;Let's suppose your app is a developer marketplace and you have a list of developers defined by this TypeScript type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Developer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;preferredLanguage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;canDesign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;hobby&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;let's define a function to load the data source from the server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dataSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://infinite-table.com/.netlify/functions/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; 
   &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json-server/developers1k-sql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Developer&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, so let's define our &lt;code&gt;DataSource&lt;/code&gt; component to use the data function above - we'll use the &lt;code&gt;id&lt;/code&gt; property as the primary key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DataSource&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@infinite-table/infinite-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DataSource&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Developer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dataSource&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;primaryKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But wait, we need to actually render the table, inside the &lt;code&gt;DataSource&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InfiniteTablePropColumns&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Developer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;preferredLanguage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preferredLanguage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;salary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;country&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataSource&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="na"&gt;Developer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  data=&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dataSource&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  primaryKey="id"
&amp;gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InfiniteTable&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="na"&gt;Developer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; columns=&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; /&amp;gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's visualise what we have to this point&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/sandpack-project-forked-3evklb?view=preview"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Now let's add the interesting part - the grouping. Grouping is a prop of the &lt;code&gt;DataSource&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;groupBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;country&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}];&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DataSource&lt;/span&gt; &lt;span class="nx"&gt;groupBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;groupBy&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would indeed group all the data, but in addition to that, we want to have some aggregation - let's find out the average salary by country. For this, we'll use aggregation reducers, defined as an object with multiple keys, on the &lt;code&gt;DataSource&lt;/code&gt;. If you're familiar with Array.reduce, those should sound familiar - the job of those aggregation reducers is to ...well, reduce 😉 ... the whole datasource to a single value (also the groups inside the datasource to single values).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aggregations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;avgSalary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;salary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;initialValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;DataSourcePropAggregationReducers&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Developer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above snippet, we're saying we have an aggregation, with the id of &lt;code&gt;avgSalary&lt;/code&gt;, that's computed based on the &lt;code&gt;salary&lt;/code&gt; field. The initial value of the aggregation is 0, and the reducer function is the &lt;code&gt;sum&lt;/code&gt; function. We also have a last step, described by the &lt;code&gt;done&lt;/code&gt; function, which does some post-processing, computing the average.&lt;/p&gt;

&lt;p&gt;Also, because the &lt;code&gt;country&lt;/code&gt; column is grouped by, we'll remove it from the list of columns that we want to show. &lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/grouping-avg-salary-by-country-forked-ugqdog?view=preview"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We're almost there, so hang on - we'll only add 1 more thing - let's try to format the salary column a bit better. We can use the &lt;code&gt;valueFormatter&lt;/code&gt; property for the salary column, and we want to format the numbers by using &lt;code&gt;Intl.NumberFormat&lt;/code&gt;. Also, for group rows, we want the value to have &lt;code&gt;Avg: ...&lt;/code&gt; prepended, while non-group rows will remain untouched.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numberFormatter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Intl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NumberFormat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// the salary column&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;salary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;valueFormatter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rowInfo&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numberFormatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rowInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isGroupRow&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`Avg: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/grouping-avg-salary-by-country-23cej1?view=preview"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We finally got to the end, ... that was quite a ride, so thank you for following along. For more in-depth documentation, see &lt;a href="https://infinite-table.com/docs/latest/learn/grouping-and-pivoting/grouping-rows"&gt;Infinite Table grouping page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Follow us along our infinite journey (pun intended) as in the next posts we'll be exploring more ways to group data, strategies for grouping, remote integration, pivoting and more, to make visualising data easier than never.&lt;/p&gt;

&lt;p&gt;Oh, and by the way, check out &lt;a href="https://dev.to/roblotter/multiple-sorting-for-your-react-project-44jh"&gt;Multiple sorting for your React project&lt;/a&gt; if you haven't already.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Multiple sorting for your React project</title>
      <dc:creator>Infinite Table</dc:creator>
      <pubDate>Tue, 24 May 2022 20:55:51 +0000</pubDate>
      <link>https://dev.to/get_infinite/multiple-sorting-for-your-react-project-44jh</link>
      <guid>https://dev.to/get_infinite/multiple-sorting-for-your-react-project-44jh</guid>
      <description>&lt;p&gt;&lt;a href="https://infinite-table.com/"&gt;https://infinite-table.com/&lt;/a&gt; is a new alternative for React projects that helps you display huge amounts of data, by using full virtualization.&lt;/p&gt;

&lt;p&gt;In this demo, I want to show you how easy it is to have your data-source sorted using multiple fields.&lt;/p&gt;

&lt;p&gt;We'll use a data-source that lists developers, with their first name, last name, age, country, city, salary and a few other fields&lt;/p&gt;

&lt;p&gt;First, you need to import the &lt;code&gt;InfiniteTable&lt;/code&gt; component and the &lt;code&gt;DataSource&lt;/code&gt; component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;InfiniteTable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@infinite-table/infinite-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, since the component is built in &lt;code&gt;Typescript&lt;/code&gt;, you can define the type of your data-source items, so let's define the TS type for that&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Developer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;preferredLanguage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;canDesign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;hobby&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next thing we have to do is define a function to load the data from the server, and that's as easy as a fetch request&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dataSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://infinite-table.com/.netlify/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; 
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;functions/json-server/developers1k&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Developer&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we're ready to render the &lt;code&gt;DataSource&lt;/code&gt; component - please note it accepts a generic type, so it will be rendered as &lt;code&gt;&amp;lt;DataSource&amp;lt;Developer&amp;gt; .../&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataSource&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="na"&gt;Developer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  primaryKey="id"
  data=&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dataSource&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&amp;gt;
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And where's the table component? Well, we'll nest it inside the &lt;code&gt;DataSource&lt;/code&gt;. But first we need some columns for the table, so let's define a map of columns&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;columns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;defaultWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stack&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preferredLanguage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;country&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can define any columns you want, and even map more columns to the same field from the &lt;code&gt;DataSource&lt;/code&gt; - but that's for another article.&lt;/p&gt;

&lt;p&gt;Now that we have the columns, we're ready to render the table as well,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataSource&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="na"&gt;Developer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; primaryKey="id" data=&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dataSource&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&amp;gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InfiniteTable&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="na"&gt;Developer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; columns=&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; /&amp;gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oh, and let's add sorting. Sorting is a concern for the data-source, so that should be a prop of the &lt;code&gt;DataSource&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataSource&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="na"&gt;Developer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  primaryKey="id"
  data=&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dataSource&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  defaultSortInfo=&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stack&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preferredLanguage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;country&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&amp;gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InfiniteTable&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="na"&gt;Developer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; columns=&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; /&amp;gt; 
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sorting is multiple sorting - so we're using an array - it clearly sends a message that there are multiple sorting properties being applied. For single sorting, use an object. Also, note the prop is called &lt;code&gt;defaultSortInfo&lt;/code&gt;, as it's uncontrolled.&lt;br&gt;
You could use the controlled &lt;code&gt;sortInfo&lt;/code&gt;, but that's useful when you want to sort the array yourself, but just communicate to the table the sorting order, in order for it to show the correct UI details for sorting. But that's another story.&lt;/p&gt;

&lt;p&gt;See the code in action below, and find out more about it at &lt;a href="https://infinite-table.com/docs/latest/learn/working-with-data/sorting"&gt;infinite-table.com&lt;/a&gt;&lt;br&gt;
&lt;iframe src="https://codesandbox.io/embed/sandpack-project-forked-cm0pmj"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
